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 #define QTDEMUX_FIRST_STREAM(demux) ((QtDemuxStream *)(demux)->active_streams \
104 ? (QtDemuxStream *)(demux)->active_streams->data : NULL)
105 #define QTDEMUX_STREAM(s) ((QtDemuxStream *)(s))
107 GST_DEBUG_CATEGORY (qtdemux_debug);
108 #define GST_CAT_DEFAULT qtdemux_debug
110 typedef struct _QtDemuxSegment QtDemuxSegment;
111 typedef struct _QtDemuxSample QtDemuxSample;
113 typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo;
115 struct _QtDemuxSample
118 gint32 pts_offset; /* Add this value to timestamp to get the pts */
120 guint64 timestamp; /* DTS In mov time */
121 guint32 duration; /* In mov time */
122 gboolean keyframe; /* TRUE when this packet is a keyframe */
125 /* Macros for converting to/from timescale */
126 #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale))
127 #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND))
129 #define QTTIME_TO_GSTTIME(qtdemux, value) (gst_util_uint64_scale((value), GST_SECOND, (qtdemux)->timescale))
130 #define GSTTIME_TO_QTTIME(qtdemux, value) (gst_util_uint64_scale((value), (qtdemux)->timescale, GST_SECOND))
132 /* timestamp is the DTS */
133 #define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp))
134 /* timestamp + offset + cslg_shift is the outgoing PTS */
135 #define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (stream)->cslg_shift + (sample)->pts_offset))
136 /* timestamp + offset is the PTS used for internal seek calcuations */
137 #define QTSAMPLE_PTS_NO_CSLG(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (sample)->pts_offset))
138 /* timestamp + duration - dts is the duration */
139 #define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts))
141 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
144 * Quicktime has tracks and segments. A track is a continuous piece of
145 * multimedia content. The track is not always played from start to finish but
146 * instead, pieces of the track are 'cut out' and played in sequence. This is
147 * what the segments do.
149 * Inside the track we have keyframes (K) and delta frames. The track has its
150 * own timing, which starts from 0 and extends to end. The position in the track
151 * is called the media_time.
153 * The segments now describe the pieces that should be played from this track
154 * and are basically tuples of media_time/duration/rate entries. We can have
155 * multiple segments and they are all played after one another. An example:
157 * segment 1: media_time: 1 second, duration: 1 second, rate 1
158 * segment 2: media_time: 3 second, duration: 2 second, rate 2
160 * To correctly play back this track, one must play: 1 second of media starting
161 * from media_time 1 followed by 2 seconds of media starting from media_time 3
164 * Each of the segments will be played at a specific time, the first segment at
165 * time 0, the second one after the duration of the first one, etc.. Note that
166 * the time in resulting playback is not identical to the media_time of the
169 * Visually, assuming the track has 4 second of media_time:
172 * .-----------------------------------------------------------.
173 * track: | K.....K.........K........K.......K.......K...........K... |
174 * '-----------------------------------------------------------'
176 * .------------^ ^ .----------^ ^
177 * / .-------------' / .------------------'
179 * .--------------. .--------------.
180 * | segment 1 | | segment 2 |
181 * '--------------' '--------------'
183 * The challenge here is to cut out the right pieces of the track for each of
184 * the playback segments. This fortunately can easily be done with the SEGMENT
185 * events of GStreamer.
187 * For playback of segment 1, we need to provide the decoder with the keyframe
188 * (a), in the above figure, but we must instruct it only to output the decoded
189 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
190 * position set to the time of the segment: 0.
192 * We then proceed to push data from keyframe (a) to frame (b). The decoder
193 * decodes but clips all before media_time 1.
195 * After finishing a segment, we push out a new SEGMENT event with the clipping
196 * boundaries of the new data.
198 * This is a good usecase for the GStreamer accumulated SEGMENT events.
201 struct _QtDemuxSegment
203 /* global time and duration, all gst time */
205 GstClockTime stop_time;
206 GstClockTime duration;
207 /* media time of trak, all gst time */
208 GstClockTime media_start;
209 GstClockTime media_stop;
211 /* Media start time in trak timescale units */
212 guint32 trak_media_start;
215 #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
217 /* Used with fragmented MP4 files (mfra atom) */
222 } QtDemuxRandomAccessEntry;
224 typedef struct _QtDemuxStreamStsdEntry
235 /* Numerator/denominator framerate */
238 GstVideoColorimetry colorimetry;
239 guint16 bits_per_sample;
240 guint16 color_table_id;
241 GstMemory *rgb8_palette;
242 guint interlace_mode;
248 guint samples_per_packet;
249 guint samples_per_frame;
250 guint bytes_per_packet;
251 guint bytes_per_sample;
252 guint bytes_per_frame;
255 /* if we use chunks or samples */
259 } QtDemuxStreamStsdEntry;
261 #define CUR_STREAM(s) (&((s)->stsd_entries[(s)->cur_stsd_entry_index]))
263 struct _QtDemuxStream
270 QtDemuxStreamStsdEntry *stsd_entries;
271 guint stsd_entries_length;
272 guint cur_stsd_entry_index;
277 gboolean new_caps; /* If TRUE, caps need to be generated (by
278 * calling _configure_stream()) This happens
279 * for MSS and fragmented streams */
281 gboolean new_stream; /* signals that a stream_start is required */
282 gboolean on_keyframe; /* if this stream last pushed buffer was a
283 * keyframe. This is important to identify
284 * where to stop pushing buffers after a
285 * segment stop time */
287 /* if the stream has a redirect URI in its headers, we store it here */
294 guint64 duration; /* in timescale units */
298 gchar lang_id[4]; /* ISO 639-2T language code */
302 QtDemuxSample *samples;
303 gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */
304 guint32 first_duration; /* duration in timescale of first sample, used for figuring out
306 guint32 n_samples_moof; /* sample count in a moof */
307 guint64 duration_moof; /* duration in timescale of a moof, used for figure out
308 * the framerate of fragmented format stream */
309 guint64 duration_last_moof;
311 guint32 offset_in_sample; /* Offset in the current sample, used for
312 * streams which have got exceedingly big
313 * sample size (such as 24s of raw audio).
314 * Only used when max_buffer_size is non-NULL */
315 guint32 max_buffer_size; /* Maximum allowed size for output buffers.
316 * Currently only set for raw audio streams*/
324 gboolean use_allocator;
325 GstAllocator *allocator;
326 GstAllocationParams params;
330 /* when a discontinuity is pending */
333 /* list of buffers to push first */
336 /* if we need to clip this buffer. This is only needed for uncompressed
340 /* buffer needs some custom processing, e.g. subtitles */
341 gboolean need_process;
343 /* current position */
344 guint32 segment_index;
345 guint32 sample_index;
346 GstClockTime time_position; /* in gst time */
347 guint64 accumulated_base;
349 /* the Gst segment we are processing out, used for clipping */
352 /* quicktime segments */
354 QtDemuxSegment *segments;
355 gboolean dummy_segment;
360 GstTagList *stream_tags;
361 gboolean send_global_tags;
363 GstEvent *pending_event;
373 gboolean chunks_are_samples; /* TRUE means treat chunks as samples */
377 GstByteReader co_chunk;
379 guint32 current_chunk;
381 guint32 samples_per_chunk;
382 guint32 stsd_sample_description_id;
383 guint32 stco_sample_index;
385 guint32 sample_size; /* 0 means variable sizes are stored in stsz */
388 guint32 n_samples_per_chunk;
389 guint32 stsc_chunk_index;
390 guint32 stsc_sample_index;
391 guint64 chunk_offset;
394 guint32 stts_samples;
395 guint32 n_sample_times;
396 guint32 stts_sample_index;
398 guint32 stts_duration;
400 gboolean stss_present;
401 guint32 n_sample_syncs;
404 gboolean stps_present;
405 guint32 n_sample_partial_syncs;
407 QtDemuxRandomAccessEntry *ra_entries;
410 const QtDemuxRandomAccessEntry *pending_seek;
413 gboolean ctts_present;
414 guint32 n_composition_times;
416 guint32 ctts_sample_index;
424 gboolean parsed_trex;
425 guint32 def_sample_description_index; /* index is 1-based */
426 guint32 def_sample_duration;
427 guint32 def_sample_size;
428 guint32 def_sample_flags;
432 /* stereoscopic video streams */
433 GstVideoMultiviewMode multiview_mode;
434 GstVideoMultiviewFlags multiview_flags;
436 /* protected streams */
438 guint32 protection_scheme_type;
439 guint32 protection_scheme_version;
440 gpointer protection_scheme_info; /* specific to the protection scheme */
441 GQueue protection_scheme_event_queue;
444 /* Contains properties and cryptographic info for a set of samples from a
445 * track protected using Common Encryption (cenc) */
446 struct _QtDemuxCencSampleSetInfo
448 GstStructure *default_properties;
450 /* @crypto_info holds one GstStructure per sample */
451 GPtrArray *crypto_info;
455 qt_demux_state_string (enum QtDemuxState state)
458 case QTDEMUX_STATE_INITIAL:
460 case QTDEMUX_STATE_HEADER:
462 case QTDEMUX_STATE_MOVIE:
464 case QTDEMUX_STATE_BUFFER_MDAT:
465 return "<BUFFER_MDAT>";
471 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
472 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
473 guint32 fourcc, GstByteReader * parser);
474 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
475 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
476 guint32 fourcc, GstByteReader * parser);
478 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
480 static GstStaticPadTemplate gst_qtdemux_sink_template =
481 GST_STATIC_PAD_TEMPLATE ("sink",
484 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
488 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
489 GST_STATIC_PAD_TEMPLATE ("video_%u",
492 GST_STATIC_CAPS_ANY);
494 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
495 GST_STATIC_PAD_TEMPLATE ("audio_%u",
498 GST_STATIC_CAPS_ANY);
500 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
501 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
504 GST_STATIC_CAPS_ANY);
506 #define gst_qtdemux_parent_class parent_class
507 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
509 static void gst_qtdemux_dispose (GObject * object);
512 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
513 GstClockTime media_time);
515 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
516 QtDemuxStream * str, gint64 media_offset);
519 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
520 static GstIndex *gst_qtdemux_get_index (GstElement * element);
522 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
523 GstStateChange transition);
524 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
525 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
526 GstObject * parent, GstPadMode mode, gboolean active);
528 static void gst_qtdemux_loop (GstPad * pad);
529 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
531 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
533 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
534 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
535 QtDemuxStream * stream);
536 static void gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
537 QtDemuxStream * stream);
538 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
541 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
542 const guint8 * buffer, guint length);
543 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
544 const guint8 * buffer, guint length);
545 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
546 static void qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist,
549 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
550 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, GNode * esds,
552 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
553 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
554 const guint8 * stsd_entry_data, gchar ** codec_name);
555 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
556 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
557 const guint8 * data, int len, gchar ** codec_name);
558 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
559 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
560 gchar ** codec_name);
561 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
562 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
563 const guint8 * stsd_entry_data, gchar ** codec_name);
565 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
566 QtDemuxStream * stream, guint32 n);
567 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
568 static void gst_qtdemux_stream_free (QtDemuxStream * stream);
569 static void gst_qtdemux_stream_clear (QtDemuxStream * stream);
570 static void gst_qtdemux_remove_stream (GstQTDemux * qtdemux,
571 QtDemuxStream * stream);
572 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
573 static void qtdemux_do_allocation (GstQTDemux * qtdemux,
574 QtDemuxStream * stream);
575 static gboolean gst_qtdemux_activate_segment (GstQTDemux * qtdemux,
576 QtDemuxStream * stream, guint32 seg_idx, GstClockTime offset);
577 static gboolean gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux,
578 QtDemuxStream * stream, gint seg_idx, GstClockTime offset,
579 GstClockTime * _start, GstClockTime * _stop);
580 static void gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
581 QtDemuxStream * stream, gint segment_index, GstClockTime pos);
583 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
584 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
586 static gchar *qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes);
588 static GstStructure *qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
589 QtDemuxStream * stream, guint sample_index);
590 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
592 static void qtdemux_gst_structure_free (GstStructure * gststructure);
595 gst_qtdemux_class_init (GstQTDemuxClass * klass)
597 GObjectClass *gobject_class;
598 GstElementClass *gstelement_class;
600 gobject_class = (GObjectClass *) klass;
601 gstelement_class = (GstElementClass *) klass;
603 parent_class = g_type_class_peek_parent (klass);
605 gobject_class->dispose = gst_qtdemux_dispose;
607 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
609 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
610 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
613 gst_tag_register_musicbrainz_tags ();
615 gst_element_class_add_static_pad_template (gstelement_class,
616 &gst_qtdemux_sink_template);
617 gst_element_class_add_static_pad_template (gstelement_class,
618 &gst_qtdemux_videosrc_template);
619 gst_element_class_add_static_pad_template (gstelement_class,
620 &gst_qtdemux_audiosrc_template);
621 gst_element_class_add_static_pad_template (gstelement_class,
622 &gst_qtdemux_subsrc_template);
623 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
625 "Demultiplex a QuickTime file into audio and video streams",
626 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
628 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
633 gst_qtdemux_init (GstQTDemux * qtdemux)
636 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
637 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
638 gst_pad_set_activatemode_function (qtdemux->sinkpad,
639 qtdemux_sink_activate_mode);
640 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
641 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
642 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
644 qtdemux->state = QTDEMUX_STATE_INITIAL;
645 qtdemux->pullbased = FALSE;
646 qtdemux->posted_redirect = FALSE;
647 qtdemux->neededbytes = 16;
649 qtdemux->adapter = gst_adapter_new ();
651 qtdemux->first_mdat = -1;
652 qtdemux->got_moov = FALSE;
653 qtdemux->mdatoffset = -1;
654 qtdemux->mdatbuffer = NULL;
655 qtdemux->restoredata_buffer = NULL;
656 qtdemux->restoredata_offset = -1;
657 qtdemux->fragment_start = -1;
658 qtdemux->fragment_start_offset = -1;
659 qtdemux->media_caps = NULL;
660 qtdemux->exposed = FALSE;
661 qtdemux->mss_mode = FALSE;
662 qtdemux->pending_newsegment = NULL;
663 qtdemux->upstream_format_is_time = FALSE;
664 qtdemux->have_group_id = FALSE;
665 qtdemux->group_id = G_MAXUINT;
666 qtdemux->cenc_aux_info_offset = 0;
667 qtdemux->cenc_aux_info_sizes = NULL;
668 qtdemux->cenc_aux_sample_count = 0;
669 qtdemux->protection_system_ids = NULL;
670 g_queue_init (&qtdemux->protection_event_queue);
671 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
672 qtdemux->tag_list = gst_tag_list_new_empty ();
673 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
674 qtdemux->flowcombiner = gst_flow_combiner_new ();
676 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
680 gst_qtdemux_dispose (GObject * object)
682 GstQTDemux *qtdemux = GST_QTDEMUX (object);
684 if (qtdemux->adapter) {
685 g_object_unref (G_OBJECT (qtdemux->adapter));
686 qtdemux->adapter = NULL;
688 gst_tag_list_unref (qtdemux->tag_list);
689 gst_flow_combiner_free (qtdemux->flowcombiner);
690 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
692 g_queue_clear (&qtdemux->protection_event_queue);
694 g_free (qtdemux->cenc_aux_info_sizes);
695 qtdemux->cenc_aux_info_sizes = NULL;
697 G_OBJECT_CLASS (parent_class)->dispose (object);
701 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
703 if (qtdemux->posted_redirect) {
704 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
705 (_("This file contains no playable streams.")),
706 ("no known streams found, a redirect message has been posted"));
708 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
709 (_("This file contains no playable streams.")),
710 ("no known streams found"));
715 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
717 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
718 mem, size, 0, size, mem, free_func);
722 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
729 if (G_UNLIKELY (size == 0)) {
731 GstBuffer *tmp = NULL;
733 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
734 if (ret != GST_FLOW_OK)
737 gst_buffer_map (tmp, &map, GST_MAP_READ);
738 size = QT_UINT32 (map.data);
739 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
741 gst_buffer_unmap (tmp, &map);
742 gst_buffer_unref (tmp);
745 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
746 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
747 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
748 /* we're pulling header but already got most interesting bits,
749 * so never mind the rest (e.g. tags) (that much) */
750 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
754 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
755 (_("This file is invalid and cannot be played.")),
756 ("atom has bogus size %" G_GUINT64_FORMAT, size));
757 return GST_FLOW_ERROR;
761 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
763 if (G_UNLIKELY (flow != GST_FLOW_OK))
766 bsize = gst_buffer_get_size (*buf);
767 /* Catch short reads - we don't want any partial atoms */
768 if (G_UNLIKELY (bsize < size)) {
769 GST_WARNING_OBJECT (qtdemux,
770 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
771 gst_buffer_unref (*buf);
781 gst_qtdemux_src_convert (GstQTDemux * qtdemux, GstPad * pad,
782 GstFormat src_format, gint64 src_value, GstFormat dest_format,
786 QtDemuxStream *stream = gst_pad_get_element_private (pad);
789 if (stream->subtype != FOURCC_vide) {
794 switch (src_format) {
795 case GST_FORMAT_TIME:
796 switch (dest_format) {
797 case GST_FORMAT_BYTES:{
798 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
804 *dest_value = stream->samples[index].offset;
806 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
807 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
808 GST_TIME_ARGS (src_value), *dest_value);
816 case GST_FORMAT_BYTES:
817 switch (dest_format) {
818 case GST_FORMAT_TIME:{
820 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
829 QTSTREAMTIME_TO_GSTTIME (stream,
830 stream->samples[index].timestamp);
831 GST_DEBUG_OBJECT (qtdemux,
832 "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
833 GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
852 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
854 gboolean res = FALSE;
856 *duration = GST_CLOCK_TIME_NONE;
858 if (qtdemux->duration != 0 &&
859 qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
860 *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
863 *duration = GST_CLOCK_TIME_NONE;
870 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
873 gboolean res = FALSE;
874 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
876 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
878 switch (GST_QUERY_TYPE (query)) {
879 case GST_QUERY_POSITION:{
882 gst_query_parse_position (query, &fmt, NULL);
883 if (fmt == GST_FORMAT_TIME
884 && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
885 gst_query_set_position (query, GST_FORMAT_TIME,
886 qtdemux->segment.position);
891 case GST_QUERY_DURATION:{
894 gst_query_parse_duration (query, &fmt, NULL);
895 if (fmt == GST_FORMAT_TIME) {
896 /* First try to query upstream */
897 res = gst_pad_query_default (pad, parent, query);
899 GstClockTime duration;
900 if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
901 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
908 case GST_QUERY_CONVERT:{
909 GstFormat src_fmt, dest_fmt;
910 gint64 src_value, dest_value = 0;
912 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
914 res = gst_qtdemux_src_convert (qtdemux, pad,
915 src_fmt, src_value, dest_fmt, &dest_value);
917 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
921 case GST_QUERY_FORMATS:
922 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
925 case GST_QUERY_SEEKING:{
929 /* try upstream first */
930 res = gst_pad_query_default (pad, parent, query);
933 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
934 if (fmt == GST_FORMAT_TIME) {
935 GstClockTime duration;
937 gst_qtdemux_get_duration (qtdemux, &duration);
939 if (!qtdemux->pullbased) {
942 /* we might be able with help from upstream */
944 q = gst_query_new_seeking (GST_FORMAT_BYTES);
945 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
946 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
947 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
951 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
957 case GST_QUERY_SEGMENT:
962 format = qtdemux->segment.format;
965 gst_segment_to_stream_time (&qtdemux->segment, format,
966 qtdemux->segment.start);
967 if ((stop = qtdemux->segment.stop) == -1)
968 stop = qtdemux->segment.duration;
970 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
972 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
977 res = gst_pad_query_default (pad, parent, query);
985 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
987 if (G_LIKELY (stream->pad)) {
988 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
989 GST_DEBUG_PAD_NAME (stream->pad));
991 if (!gst_tag_list_is_empty (stream->stream_tags)) {
992 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
993 stream->stream_tags);
994 gst_pad_push_event (stream->pad,
995 gst_event_new_tag (gst_tag_list_ref (stream->stream_tags)));
998 if (G_UNLIKELY (stream->send_global_tags)) {
999 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
1001 gst_pad_push_event (stream->pad,
1002 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
1003 stream->send_global_tags = FALSE;
1008 /* push event on all source pads; takes ownership of the event */
1010 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
1012 gboolean has_valid_stream = FALSE;
1013 GstEventType etype = GST_EVENT_TYPE (event);
1016 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
1017 GST_EVENT_TYPE_NAME (event));
1019 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
1021 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
1022 GST_DEBUG_OBJECT (qtdemux, "pushing on track-id %u", stream->track_id);
1024 if ((pad = stream->pad)) {
1025 has_valid_stream = TRUE;
1027 if (etype == GST_EVENT_EOS) {
1028 /* let's not send twice */
1029 if (stream->sent_eos)
1031 stream->sent_eos = TRUE;
1034 gst_pad_push_event (pad, gst_event_ref (event));
1038 gst_event_unref (event);
1040 /* if it is EOS and there are no pads, post an error */
1041 if (!has_valid_stream && etype == GST_EVENT_EOS) {
1042 gst_qtdemux_post_no_playable_stream_error (qtdemux);
1046 /* push a pending newsegment event, if any from the streaming thread */
1048 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
1050 if (qtdemux->pending_newsegment) {
1051 gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
1052 qtdemux->pending_newsegment = NULL;
1062 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
1064 if ((gint64) s1->timestamp > *media_time)
1066 if ((gint64) s1->timestamp == *media_time)
1072 /* find the index of the sample that includes the data for @media_time using a
1073 * binary search. Only to be called in optimized cases of linear search below.
1075 * Returns the index of the sample with the corresponding *DTS*.
1078 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
1081 QtDemuxSample *result;
1084 /* convert media_time to mov format */
1086 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1088 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
1089 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
1090 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
1092 if (G_LIKELY (result))
1093 index = result - str->samples;
1102 /* find the index of the sample that includes the data for @media_offset using a
1105 * Returns the index of the sample.
1108 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
1109 QtDemuxStream * str, gint64 media_offset)
1111 QtDemuxSample *result = str->samples;
1114 if (result == NULL || str->n_samples == 0)
1117 if (media_offset == result->offset)
1121 while (index < str->n_samples - 1) {
1122 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1125 if (media_offset < result->offset)
1136 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1141 /* find the index of the sample that includes the data for @media_time using a
1142 * linear search, and keeping in mind that not all samples may have been parsed
1143 * yet. If possible, it will delegate to binary search.
1145 * Returns the index of the sample.
1148 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
1149 GstClockTime media_time)
1153 QtDemuxSample *sample;
1155 /* convert media_time to mov format */
1157 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1159 sample = str->samples;
1160 if (mov_time == sample->timestamp + sample->pts_offset)
1163 /* use faster search if requested time in already parsed range */
1164 sample = str->samples + str->stbl_index;
1165 if (str->stbl_index >= 0 && mov_time <= sample->timestamp) {
1166 index = gst_qtdemux_find_index (qtdemux, str, media_time);
1167 sample = str->samples + index;
1169 while (index < str->n_samples - 1) {
1170 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1173 sample = str->samples + index + 1;
1174 if (mov_time < sample->timestamp) {
1175 sample = str->samples + index;
1183 /* sample->timestamp is now <= media_time, need to find the corresponding
1184 * PTS now by looking backwards */
1185 while (index > 0 && sample->timestamp + sample->pts_offset > mov_time) {
1187 sample = str->samples + index;
1195 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1200 /* find the index of the keyframe needed to decode the sample at @index
1201 * of stream @str, or of a subsequent keyframe (depending on @next)
1203 * Returns the index of the keyframe.
1206 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1207 guint32 index, gboolean next)
1209 guint32 new_index = index;
1211 if (index >= str->n_samples) {
1212 new_index = str->n_samples;
1216 /* all keyframes, return index */
1217 if (str->all_keyframe) {
1222 /* else search until we have a keyframe */
1223 while (new_index < str->n_samples) {
1224 if (next && !qtdemux_parse_samples (qtdemux, str, new_index))
1227 if (str->samples[new_index].keyframe)
1239 if (new_index == str->n_samples) {
1240 GST_DEBUG_OBJECT (qtdemux, "no next keyframe");
1245 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index %s index %u "
1246 "gave %u", next ? "after" : "before", index, new_index);
1253 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", new_index);
1258 /* find the segment for @time_position for @stream
1260 * Returns the index of the segment containing @time_position.
1261 * Returns the last segment and sets the @eos variable to TRUE
1262 * if the time is beyond the end. @eos may be NULL
1265 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1266 GstClockTime time_position)
1271 GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1272 GST_TIME_ARGS (time_position));
1275 for (i = 0; i < stream->n_segments; i++) {
1276 QtDemuxSegment *segment = &stream->segments[i];
1278 GST_LOG_OBJECT (stream->pad,
1279 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1280 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1282 /* For the last segment we include stop_time in the last segment */
1283 if (i < stream->n_segments - 1) {
1284 if (segment->time <= time_position && time_position < segment->stop_time) {
1285 GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1290 /* Last segment always matches */
1298 /* move the stream @str to the sample position @index.
1300 * Updates @str->sample_index and marks discontinuity if needed.
1303 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1306 /* no change needed */
1307 if (index == str->sample_index)
1310 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1313 /* position changed, we have a discont */
1314 str->sample_index = index;
1315 str->offset_in_sample = 0;
1316 /* Each time we move in the stream we store the position where we are
1318 str->from_sample = index;
1319 str->discont = TRUE;
1323 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1324 gboolean use_sparse, gboolean next, gint64 * key_time, gint64 * key_offset)
1327 gint64 min_byte_offset = -1;
1330 min_offset = desired_time;
1332 /* for each stream, find the index of the sample in the segment
1333 * and move back to the previous keyframe. */
1334 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
1336 guint32 index, kindex;
1338 GstClockTime media_start;
1339 GstClockTime media_time;
1340 GstClockTime seg_time;
1341 QtDemuxSegment *seg;
1342 gboolean empty_segment = FALSE;
1344 str = QTDEMUX_STREAM (iter->data);
1346 if (CUR_STREAM (str)->sparse && !use_sparse)
1349 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1350 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1352 /* get segment and time in the segment */
1353 seg = &str->segments[seg_idx];
1354 seg_time = (desired_time - seg->time) * seg->rate;
1356 while (QTSEGMENT_IS_EMPTY (seg)) {
1358 empty_segment = TRUE;
1359 GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1362 if (seg_idx == str->n_segments)
1364 seg = &str->segments[seg_idx];
1367 if (seg_idx == str->n_segments) {
1368 /* FIXME track shouldn't have the last segment as empty, but if it
1369 * happens we better handle it */
1373 /* get the media time in the segment */
1374 media_start = seg->media_start + seg_time;
1376 /* get the index of the sample with media time */
1377 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1378 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1379 " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1380 GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1383 /* shift to next frame if we are looking for next keyframe */
1384 if (next && QTSAMPLE_PTS_NO_CSLG (str, &str->samples[index]) < media_start
1385 && index < str->stbl_index)
1388 if (!empty_segment) {
1389 /* find previous keyframe */
1390 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, next);
1392 /* we will settle for one before if none found after */
1393 if (next && kindex == -1)
1394 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
1396 /* if the keyframe is at a different position, we need to update the
1397 * requested seek time */
1398 if (index != kindex) {
1401 /* get timestamp of keyframe */
1402 media_time = QTSAMPLE_PTS_NO_CSLG (str, &str->samples[kindex]);
1403 GST_DEBUG_OBJECT (qtdemux,
1404 "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1405 G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1406 str->samples[kindex].offset);
1408 /* keyframes in the segment get a chance to change the
1409 * desired_offset. keyframes out of the segment are
1411 if (media_time >= seg->media_start) {
1412 GstClockTime seg_time;
1414 /* this keyframe is inside the segment, convert back to
1416 seg_time = (media_time - seg->media_start) + seg->time;
1417 if ((!next && (seg_time < min_offset)) ||
1418 (next && (seg_time > min_offset)))
1419 min_offset = seg_time;
1424 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1425 min_byte_offset = str->samples[index].offset;
1429 *key_time = min_offset;
1431 *key_offset = min_byte_offset;
1435 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1436 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1440 g_return_val_if_fail (format != NULL, FALSE);
1441 g_return_val_if_fail (cur != NULL, FALSE);
1442 g_return_val_if_fail (stop != NULL, FALSE);
1444 if (*format == GST_FORMAT_TIME)
1448 if (cur_type != GST_SEEK_TYPE_NONE)
1449 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1450 if (res && stop_type != GST_SEEK_TYPE_NONE)
1451 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1454 *format = GST_FORMAT_TIME;
1459 /* perform seek in push based mode:
1460 find BYTE position to move to based on time and delegate to upstream
1463 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1468 GstSeekType cur_type, stop_type;
1469 gint64 cur, stop, key_cur;
1472 gint64 original_stop;
1475 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1477 gst_event_parse_seek (event, &rate, &format, &flags,
1478 &cur_type, &cur, &stop_type, &stop);
1479 seqnum = gst_event_get_seqnum (event);
1481 /* only forward streaming and seeking is possible */
1483 goto unsupported_seek;
1485 /* convert to TIME if needed and possible */
1486 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1490 /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1491 * the original stop position to use when upstream pushes the new segment
1493 original_stop = stop;
1496 /* find reasonable corresponding BYTE position,
1497 * also try to mind about keyframes, since we can not go back a bit for them
1499 /* determining @next here based on SNAP_BEFORE/SNAP_AFTER should
1500 * mostly just work, but let's not yet boldly go there ... */
1501 gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, FALSE, &key_cur, &byte_cur);
1506 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1507 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1510 GST_OBJECT_LOCK (qtdemux);
1511 qtdemux->seek_offset = byte_cur;
1512 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1513 qtdemux->push_seek_start = cur;
1515 qtdemux->push_seek_start = key_cur;
1518 if (stop_type == GST_SEEK_TYPE_NONE) {
1519 qtdemux->push_seek_stop = qtdemux->segment.stop;
1521 qtdemux->push_seek_stop = original_stop;
1523 GST_OBJECT_UNLOCK (qtdemux);
1525 /* BYTE seek event */
1526 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1528 gst_event_set_seqnum (event, seqnum);
1529 res = gst_pad_push_event (qtdemux->sinkpad, event);
1536 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1542 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1547 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1552 /* perform the seek.
1554 * We set all segment_indexes in the streams to unknown and
1555 * adjust the time_position to the desired position. this is enough
1556 * to trigger a segment switch in the streaming thread to start
1557 * streaming from the desired position.
1559 * Keyframe seeking is a little more complicated when dealing with
1560 * segments. Ideally we want to move to the previous keyframe in
1561 * the segment but there might not be a keyframe in the segment. In
1562 * fact, none of the segments could contain a keyframe. We take a
1563 * practical approach: seek to the previous keyframe in the segment,
1564 * if there is none, seek to the beginning of the segment.
1566 * Called with STREAM_LOCK
1569 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1570 guint32 seqnum, GstSeekFlags flags)
1572 gint64 desired_offset;
1575 desired_offset = segment->position;
1577 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1578 GST_TIME_ARGS (desired_offset));
1580 /* may not have enough fragmented info to do this adjustment,
1581 * and we can't scan (and probably should not) at this time with
1582 * possibly flushing upstream */
1583 if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1585 gboolean next, before, after;
1587 before = ! !(flags & GST_SEEK_FLAG_SNAP_BEFORE);
1588 after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER);
1589 next = after && !before;
1590 if (segment->rate < 0)
1593 gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, next, &min_offset,
1595 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1596 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1597 desired_offset = min_offset;
1600 /* and set all streams to the final position */
1601 gst_flow_combiner_reset (qtdemux->flowcombiner);
1602 qtdemux->segment_seqnum = seqnum;
1603 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
1604 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
1606 stream->time_position = desired_offset;
1607 stream->accumulated_base = 0;
1608 stream->sample_index = -1;
1609 stream->offset_in_sample = 0;
1610 stream->segment_index = -1;
1611 stream->sent_eos = FALSE;
1613 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1614 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1616 segment->position = desired_offset;
1617 segment->time = desired_offset;
1618 if (segment->rate >= 0) {
1619 segment->start = desired_offset;
1621 /* we stop at the end */
1622 if (segment->stop == -1)
1623 segment->stop = segment->duration;
1625 segment->stop = desired_offset;
1628 if (qtdemux->fragmented)
1629 qtdemux->fragmented_seek_pending = TRUE;
1634 /* do a seek in pull based mode */
1636 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1641 GstSeekType cur_type, stop_type;
1645 GstSegment seeksegment;
1646 guint32 seqnum = GST_SEQNUM_INVALID;
1647 GstEvent *flush_event;
1651 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1653 gst_event_parse_seek (event, &rate, &format, &flags,
1654 &cur_type, &cur, &stop_type, &stop);
1655 seqnum = gst_event_get_seqnum (event);
1657 /* we have to have a format as the segment format. Try to convert
1659 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1663 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1665 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1669 flush = flags & GST_SEEK_FLAG_FLUSH;
1671 /* stop streaming, either by flushing or by pausing the task */
1673 flush_event = gst_event_new_flush_start ();
1674 if (seqnum != GST_SEQNUM_INVALID)
1675 gst_event_set_seqnum (flush_event, seqnum);
1676 /* unlock upstream pull_range */
1677 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1678 /* make sure out loop function exits */
1679 gst_qtdemux_push_event (qtdemux, flush_event);
1681 /* non flushing seek, pause the task */
1682 gst_pad_pause_task (qtdemux->sinkpad);
1685 /* wait for streaming to finish */
1686 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1688 /* copy segment, we need this because we still need the old
1689 * segment when we close the current segment. */
1690 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1693 /* configure the segment with the seek variables */
1694 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1695 if (!gst_segment_do_seek (&seeksegment, rate, format, flags,
1696 cur_type, cur, stop_type, stop, &update)) {
1698 GST_ERROR_OBJECT (qtdemux, "inconsistent seek values, doing nothing");
1700 /* now do the seek */
1701 ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1704 /* now do the seek */
1705 ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1708 /* prepare for streaming again */
1710 flush_event = gst_event_new_flush_stop (TRUE);
1711 if (seqnum != GST_SEQNUM_INVALID)
1712 gst_event_set_seqnum (flush_event, seqnum);
1714 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1715 gst_qtdemux_push_event (qtdemux, flush_event);
1718 /* commit the new segment */
1719 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1721 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1722 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1723 qtdemux->segment.format, qtdemux->segment.position);
1724 if (seqnum != GST_SEQNUM_INVALID)
1725 gst_message_set_seqnum (msg, seqnum);
1726 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1729 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1730 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1731 qtdemux->sinkpad, NULL);
1733 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1740 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1746 qtdemux_ensure_index (GstQTDemux * qtdemux)
1750 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1752 /* Build complete index */
1753 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
1754 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
1756 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
1757 GST_LOG_OBJECT (qtdemux,
1758 "Building complete index of track-id %u for seeking failed!",
1768 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1771 gboolean res = TRUE;
1772 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1774 switch (GST_EVENT_TYPE (event)) {
1775 case GST_EVENT_SEEK:
1777 #ifndef GST_DISABLE_GST_DEBUG
1778 GstClockTime ts = gst_util_get_timestamp ();
1780 guint32 seqnum = gst_event_get_seqnum (event);
1782 if (seqnum == qtdemux->segment_seqnum) {
1783 GST_LOG_OBJECT (pad,
1784 "Drop duplicated SEEK event seqnum %" G_GUINT32_FORMAT, seqnum);
1785 gst_event_unref (event);
1789 if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1790 /* seek should be handled by upstream, we might need to re-download fragments */
1791 GST_DEBUG_OBJECT (qtdemux,
1792 "let upstream handle seek for fragmented playback");
1796 /* Build complete index for seeking;
1797 * if not a fragmented file at least */
1798 if (!qtdemux->fragmented)
1799 if (!qtdemux_ensure_index (qtdemux))
1801 #ifndef GST_DISABLE_GST_DEBUG
1802 ts = gst_util_get_timestamp () - ts;
1803 GST_INFO_OBJECT (qtdemux,
1804 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1807 if (qtdemux->pullbased) {
1808 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1809 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1810 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1812 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams
1813 && !qtdemux->fragmented) {
1814 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1816 GST_DEBUG_OBJECT (qtdemux,
1817 "ignoring seek in push mode in current state");
1820 gst_event_unref (event);
1824 res = gst_pad_event_default (pad, parent, event);
1834 GST_ERROR_OBJECT (qtdemux, "Index failed");
1835 gst_event_unref (event);
1841 /* Find, for each track, the first sample in coding order that has a file offset >= @byte_pos.
1843 * If @fw is false, the coding order is explored backwards.
1845 * If @set is true, each stream will be moved to its matched sample, or EOS if no matching
1846 * sample is found for that track.
1848 * The stream and sample index of the sample with the minimum offset in the direction explored
1849 * (see @fw) is returned in the output parameters @_stream and @_index respectively.
1851 * @_time is set to the QTSAMPLE_PTS of the matched sample with the minimum QTSAMPLE_PTS in the
1852 * direction explored, which may not always match the QTSAMPLE_PTS of the sample returned in
1853 * @_stream and @_index. */
1855 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1856 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1859 gint64 time, min_time;
1860 QtDemuxStream *stream;
1867 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
1870 gboolean set_sample;
1872 str = QTDEMUX_STREAM (iter->data);
1879 i = str->n_samples - 1;
1883 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1884 if (str->samples[i].size == 0)
1887 if (fw && (str->samples[i].offset < byte_pos))
1890 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1893 /* move stream to first available sample */
1895 gst_qtdemux_move_stream (qtdemux, str, i);
1899 /* avoid index from sparse streams since they might be far away */
1900 if (!CUR_STREAM (str)->sparse) {
1901 /* determine min/max time */
1902 time = QTSAMPLE_PTS (str, &str->samples[i]);
1903 if (min_time == -1 || (!fw && time > min_time) ||
1904 (fw && time < min_time)) {
1908 /* determine stream with leading sample, to get its position */
1910 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1911 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1919 /* no sample for this stream, mark eos */
1921 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1932 /* Copied from mpegtsbase code */
1933 /* FIXME: replace this function when we add new util function for stream-id creation */
1935 _get_upstream_id (GstQTDemux * demux)
1937 gchar *upstream_id = gst_pad_get_stream_id (demux->sinkpad);
1940 /* Try to create one from the upstream URI, else use a randome number */
1944 /* Try to generate one from the URI query and
1945 * if it fails take a random number instead */
1946 query = gst_query_new_uri ();
1947 if (gst_element_query (GST_ELEMENT_CAST (demux), query)) {
1948 gst_query_parse_uri (query, &uri);
1954 /* And then generate an SHA256 sum of the URI */
1955 cs = g_checksum_new (G_CHECKSUM_SHA256);
1956 g_checksum_update (cs, (const guchar *) uri, strlen (uri));
1958 upstream_id = g_strdup (g_checksum_get_string (cs));
1959 g_checksum_free (cs);
1961 /* Just get some random number if the URI query fails */
1962 GST_FIXME_OBJECT (demux, "Creating random stream-id, consider "
1963 "implementing a deterministic way of creating a stream-id");
1965 g_strdup_printf ("%08x%08x%08x%08x", g_random_int (), g_random_int (),
1966 g_random_int (), g_random_int ());
1969 gst_query_unref (query);
1974 static QtDemuxStream *
1975 _create_stream (GstQTDemux * demux, guint32 track_id)
1977 QtDemuxStream *stream;
1980 stream = g_new0 (QtDemuxStream, 1);
1981 stream->demux = demux;
1982 stream->track_id = track_id;
1983 upstream_id = _get_upstream_id (demux);
1984 stream->stream_id = g_strdup_printf ("%s/%03u", upstream_id, track_id);
1985 g_free (upstream_id);
1986 /* new streams always need a discont */
1987 stream->discont = TRUE;
1988 /* we enable clipping for raw audio/video streams */
1989 stream->need_clip = FALSE;
1990 stream->need_process = FALSE;
1991 stream->segment_index = -1;
1992 stream->time_position = 0;
1993 stream->sample_index = -1;
1994 stream->offset_in_sample = 0;
1995 stream->new_stream = TRUE;
1996 stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1997 stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1998 stream->protected = FALSE;
1999 stream->protection_scheme_type = 0;
2000 stream->protection_scheme_version = 0;
2001 stream->protection_scheme_info = NULL;
2002 stream->n_samples_moof = 0;
2003 stream->duration_moof = 0;
2004 stream->duration_last_moof = 0;
2005 stream->alignment = 1;
2006 stream->stream_tags = gst_tag_list_new_empty ();
2007 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
2008 g_queue_init (&stream->protection_scheme_event_queue);
2013 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
2015 GstStructure *structure;
2016 const gchar *variant;
2017 const GstCaps *mediacaps = NULL;
2019 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
2021 structure = gst_caps_get_structure (caps, 0);
2022 variant = gst_structure_get_string (structure, "variant");
2024 if (variant && strcmp (variant, "mss-fragmented") == 0) {
2025 QtDemuxStream *stream;
2026 const GValue *value;
2028 demux->fragmented = TRUE;
2029 demux->mss_mode = TRUE;
2031 if (demux->n_streams > 1) {
2032 /* can't do this, we can only renegotiate for another mss format */
2036 value = gst_structure_get_value (structure, "media-caps");
2039 const GValue *timescale_v;
2041 /* TODO update when stream changes during playback */
2043 if (demux->n_streams == 0) {
2044 stream = _create_stream (demux, 1);
2045 demux->active_streams = g_list_append (demux->active_streams, stream);
2046 demux->n_streams = 1;
2047 /* mss has no stsd/stsd entry, use id 0 as default */
2048 stream->stsd_entries_length = 1;
2049 stream->stsd_sample_description_id = stream->cur_stsd_entry_index = 0;
2050 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, 1);
2052 stream = QTDEMUX_FIRST_STREAM (demux);
2055 timescale_v = gst_structure_get_value (structure, "timescale");
2057 stream->timescale = g_value_get_uint64 (timescale_v);
2059 /* default mss timescale */
2060 stream->timescale = 10000000;
2062 demux->timescale = stream->timescale;
2064 mediacaps = gst_value_get_caps (value);
2065 if (!CUR_STREAM (stream)->caps
2066 || !gst_caps_is_equal_fixed (mediacaps, CUR_STREAM (stream)->caps)) {
2067 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
2069 stream->new_caps = TRUE;
2071 gst_caps_replace (&CUR_STREAM (stream)->caps, (GstCaps *) mediacaps);
2072 structure = gst_caps_get_structure (mediacaps, 0);
2073 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
2074 stream->subtype = FOURCC_vide;
2076 gst_structure_get_int (structure, "width", &CUR_STREAM (stream)->width);
2077 gst_structure_get_int (structure, "height",
2078 &CUR_STREAM (stream)->height);
2079 gst_structure_get_fraction (structure, "framerate",
2080 &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
2081 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
2083 stream->subtype = FOURCC_soun;
2084 gst_structure_get_int (structure, "channels",
2085 &CUR_STREAM (stream)->n_channels);
2086 gst_structure_get_int (structure, "rate", &rate);
2087 CUR_STREAM (stream)->rate = rate;
2090 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
2092 demux->mss_mode = FALSE;
2099 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
2103 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
2104 gst_pad_stop_task (qtdemux->sinkpad);
2106 if (hard || qtdemux->upstream_format_is_time) {
2107 qtdemux->state = QTDEMUX_STATE_INITIAL;
2108 qtdemux->neededbytes = 16;
2109 qtdemux->todrop = 0;
2110 qtdemux->pullbased = FALSE;
2111 qtdemux->posted_redirect = FALSE;
2112 qtdemux->first_mdat = -1;
2113 qtdemux->header_size = 0;
2114 qtdemux->mdatoffset = -1;
2115 qtdemux->restoredata_offset = -1;
2116 if (qtdemux->mdatbuffer)
2117 gst_buffer_unref (qtdemux->mdatbuffer);
2118 if (qtdemux->restoredata_buffer)
2119 gst_buffer_unref (qtdemux->restoredata_buffer);
2120 qtdemux->mdatbuffer = NULL;
2121 qtdemux->restoredata_buffer = NULL;
2122 qtdemux->mdatleft = 0;
2123 qtdemux->mdatsize = 0;
2124 if (qtdemux->comp_brands)
2125 gst_buffer_unref (qtdemux->comp_brands);
2126 qtdemux->comp_brands = NULL;
2127 qtdemux->last_moov_offset = -1;
2128 if (qtdemux->moov_node_compressed) {
2129 g_node_destroy (qtdemux->moov_node_compressed);
2130 if (qtdemux->moov_node)
2131 g_free (qtdemux->moov_node->data);
2133 qtdemux->moov_node_compressed = NULL;
2134 if (qtdemux->moov_node)
2135 g_node_destroy (qtdemux->moov_node);
2136 qtdemux->moov_node = NULL;
2137 if (qtdemux->tag_list)
2138 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
2139 qtdemux->tag_list = gst_tag_list_new_empty ();
2140 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
2142 if (qtdemux->element_index)
2143 gst_object_unref (qtdemux->element_index);
2144 qtdemux->element_index = NULL;
2146 qtdemux->major_brand = 0;
2147 if (qtdemux->pending_newsegment)
2148 gst_event_unref (qtdemux->pending_newsegment);
2149 qtdemux->pending_newsegment = NULL;
2150 qtdemux->upstream_format_is_time = FALSE;
2151 qtdemux->upstream_seekable = FALSE;
2152 qtdemux->upstream_size = 0;
2154 qtdemux->fragment_start = -1;
2155 qtdemux->fragment_start_offset = -1;
2156 qtdemux->duration = 0;
2157 qtdemux->moof_offset = 0;
2158 qtdemux->chapters_track_id = 0;
2159 qtdemux->have_group_id = FALSE;
2160 qtdemux->group_id = G_MAXUINT;
2162 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
2164 g_queue_clear (&qtdemux->protection_event_queue);
2166 qtdemux->offset = 0;
2167 gst_adapter_clear (qtdemux->adapter);
2168 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
2169 qtdemux->segment_seqnum = GST_SEQNUM_INVALID;
2172 g_list_free_full (qtdemux->active_streams,
2173 (GDestroyNotify) gst_qtdemux_stream_free);
2174 qtdemux->active_streams = NULL;
2175 qtdemux->n_streams = 0;
2176 qtdemux->n_video_streams = 0;
2177 qtdemux->n_audio_streams = 0;
2178 qtdemux->n_sub_streams = 0;
2179 qtdemux->exposed = FALSE;
2180 qtdemux->fragmented = FALSE;
2181 qtdemux->mss_mode = FALSE;
2182 gst_caps_replace (&qtdemux->media_caps, NULL);
2183 qtdemux->timescale = 0;
2184 qtdemux->got_moov = FALSE;
2185 if (qtdemux->protection_system_ids) {
2186 g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2187 qtdemux->protection_system_ids = NULL;
2189 } else if (qtdemux->mss_mode) {
2190 gst_flow_combiner_reset (qtdemux->flowcombiner);
2191 g_list_foreach (qtdemux->active_streams,
2192 (GFunc) gst_qtdemux_stream_clear, NULL);
2194 gst_flow_combiner_reset (qtdemux->flowcombiner);
2195 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
2196 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
2197 stream->sent_eos = FALSE;
2198 stream->time_position = 0;
2199 stream->accumulated_base = 0;
2201 if (!qtdemux->pending_newsegment) {
2202 qtdemux->pending_newsegment = gst_event_new_segment (&qtdemux->segment);
2203 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
2204 gst_event_set_seqnum (qtdemux->pending_newsegment,
2205 qtdemux->segment_seqnum);
2211 /* Maps the @segment to the qt edts internal segments and pushes
2212 * the correspnding segment event.
2214 * If it ends up being at a empty segment, a gap will be pushed and the next
2215 * edts segment will be activated in sequence.
2217 * To be used in push-mode only */
2219 gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
2224 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
2225 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
2227 stream->time_position = segment->start;
2229 /* in push mode we should be guaranteed that we will have empty segments
2230 * at the beginning and then one segment after, other scenarios are not
2231 * supported and are discarded when parsing the edts */
2232 for (i = 0; i < stream->n_segments; i++) {
2233 if (stream->segments[i].stop_time > segment->start) {
2234 gst_qtdemux_activate_segment (qtdemux, stream, i,
2235 stream->time_position);
2236 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
2237 /* push the empty segment and move to the next one */
2238 gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
2239 stream->time_position);
2243 g_assert (i == stream->n_segments - 1);
2250 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2253 GstQTDemux *demux = GST_QTDEMUX (parent);
2254 gboolean res = TRUE;
2256 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2258 switch (GST_EVENT_TYPE (event)) {
2259 case GST_EVENT_SEGMENT:
2262 QtDemuxStream *stream;
2266 /* some debug output */
2267 gst_event_copy_segment (event, &segment);
2268 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2271 /* erase any previously set segment */
2272 gst_event_replace (&demux->pending_newsegment, NULL);
2274 if (segment.format == GST_FORMAT_TIME) {
2275 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
2276 gst_event_replace (&demux->pending_newsegment, event);
2277 demux->upstream_format_is_time = TRUE;
2279 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2280 "not in time format");
2282 /* chain will send initial newsegment after pads have been added */
2283 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
2284 GST_DEBUG_OBJECT (demux, "still starting, eating event");
2289 /* check if this matches a time seek we received previously
2290 * FIXME for backwards compatibility reasons we use the
2291 * seek_offset here to compare. In the future we might want to
2292 * change this to use the seqnum as it uniquely should identify
2293 * the segment that corresponds to the seek. */
2294 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2295 ", received segment offset %" G_GINT64_FORMAT,
2296 demux->seek_offset, segment.start);
2297 if (segment.format == GST_FORMAT_BYTES
2298 && demux->seek_offset == segment.start) {
2299 GST_OBJECT_LOCK (demux);
2300 offset = segment.start;
2302 segment.format = GST_FORMAT_TIME;
2303 segment.start = demux->push_seek_start;
2304 segment.stop = demux->push_seek_stop;
2305 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2306 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2307 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2308 GST_OBJECT_UNLOCK (demux);
2311 /* we only expect a BYTE segment, e.g. following a seek */
2312 if (segment.format == GST_FORMAT_BYTES) {
2313 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2314 offset = segment.start;
2316 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2317 NULL, (gint64 *) & segment.start);
2318 if ((gint64) segment.start < 0)
2321 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2322 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2323 NULL, (gint64 *) & segment.stop);
2324 /* keyframe seeking should already arrange for start >= stop,
2325 * but make sure in other rare cases */
2326 segment.stop = MAX (segment.stop, segment.start);
2328 } else if (segment.format == GST_FORMAT_TIME) {
2329 /* push all data on the adapter before starting this
2331 gst_qtdemux_process_adapter (demux, TRUE);
2333 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2337 /* We shouldn't modify upstream driven TIME FORMAT segment */
2338 if (!demux->upstream_format_is_time) {
2339 /* accept upstream's notion of segment and distribute along */
2340 segment.format = GST_FORMAT_TIME;
2341 segment.position = segment.time = segment.start;
2342 segment.duration = demux->segment.duration;
2343 segment.base = gst_segment_to_running_time (&demux->segment,
2344 GST_FORMAT_TIME, demux->segment.position);
2347 gst_segment_copy_into (&segment, &demux->segment);
2348 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2350 /* map segment to internal qt segments and push on each stream */
2351 if (demux->n_streams) {
2352 if (demux->fragmented) {
2353 GstEvent *segment_event = gst_event_new_segment (&segment);
2355 gst_event_replace (&demux->pending_newsegment, NULL);
2356 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
2357 gst_qtdemux_push_event (demux, segment_event);
2359 gst_event_replace (&demux->pending_newsegment, NULL);
2360 gst_qtdemux_map_and_push_segments (demux, &segment);
2364 /* clear leftover in current segment, if any */
2365 gst_adapter_clear (demux->adapter);
2367 /* set up streaming thread */
2368 demux->offset = offset;
2369 if (demux->upstream_format_is_time) {
2370 GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2371 "set values to restart reading from a new atom");
2372 demux->neededbytes = 16;
2375 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2378 demux->todrop = stream->samples[idx].offset - offset;
2379 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2381 /* set up for EOS */
2382 demux->neededbytes = -1;
2387 gst_event_unref (event);
2391 case GST_EVENT_FLUSH_START:
2393 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2394 gst_event_unref (event);
2399 case GST_EVENT_FLUSH_STOP:
2403 dur = demux->segment.duration;
2404 gst_qtdemux_reset (demux, FALSE);
2405 demux->segment.duration = dur;
2407 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2408 gst_event_unref (event);
2414 /* If we are in push mode, and get an EOS before we've seen any streams,
2415 * then error out - we have nowhere to send the EOS */
2416 if (!demux->pullbased) {
2418 gboolean has_valid_stream = FALSE;
2419 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
2420 if (QTDEMUX_STREAM (iter->data)->pad != NULL) {
2421 has_valid_stream = TRUE;
2425 if (!has_valid_stream)
2426 gst_qtdemux_post_no_playable_stream_error (demux);
2428 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2429 (guint) gst_adapter_available (demux->adapter));
2430 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2436 case GST_EVENT_CAPS:{
2437 GstCaps *caps = NULL;
2439 gst_event_parse_caps (event, &caps);
2440 gst_qtdemux_setcaps (demux, caps);
2442 gst_event_unref (event);
2445 case GST_EVENT_PROTECTION:
2447 const gchar *system_id = NULL;
2449 gst_event_parse_protection (event, &system_id, NULL, NULL);
2450 GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2452 gst_qtdemux_append_protection_system_id (demux, system_id);
2453 /* save the event for later, for source pads that have not been created */
2454 g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2455 /* send it to all pads that already exist */
2456 gst_qtdemux_push_event (demux, event);
2460 case GST_EVENT_STREAM_START:
2463 gst_event_unref (event);
2470 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2478 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2480 GstQTDemux *demux = GST_QTDEMUX (element);
2482 GST_OBJECT_LOCK (demux);
2483 if (demux->element_index)
2484 gst_object_unref (demux->element_index);
2486 demux->element_index = gst_object_ref (index);
2488 demux->element_index = NULL;
2490 GST_OBJECT_UNLOCK (demux);
2491 /* object lock might be taken again */
2493 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2494 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2495 demux->element_index, demux->index_id);
2499 gst_qtdemux_get_index (GstElement * element)
2501 GstIndex *result = NULL;
2502 GstQTDemux *demux = GST_QTDEMUX (element);
2504 GST_OBJECT_LOCK (demux);
2505 if (demux->element_index)
2506 result = gst_object_ref (demux->element_index);
2507 GST_OBJECT_UNLOCK (demux);
2509 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2516 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2518 g_free ((gpointer) stream->stco.data);
2519 stream->stco.data = NULL;
2520 g_free ((gpointer) stream->stsz.data);
2521 stream->stsz.data = NULL;
2522 g_free ((gpointer) stream->stsc.data);
2523 stream->stsc.data = NULL;
2524 g_free ((gpointer) stream->stts.data);
2525 stream->stts.data = NULL;
2526 g_free ((gpointer) stream->stss.data);
2527 stream->stss.data = NULL;
2528 g_free ((gpointer) stream->stps.data);
2529 stream->stps.data = NULL;
2530 g_free ((gpointer) stream->ctts.data);
2531 stream->ctts.data = NULL;
2535 gst_qtdemux_stream_flush_segments_data (QtDemuxStream * stream)
2537 g_free (stream->segments);
2538 stream->segments = NULL;
2539 stream->segment_index = -1;
2540 stream->accumulated_base = 0;
2544 gst_qtdemux_stream_flush_samples_data (QtDemuxStream * stream)
2546 g_free (stream->samples);
2547 stream->samples = NULL;
2548 gst_qtdemux_stbl_free (stream);
2551 g_free (stream->ra_entries);
2552 stream->ra_entries = NULL;
2553 stream->n_ra_entries = 0;
2555 stream->sample_index = -1;
2556 stream->stbl_index = -1;
2557 stream->n_samples = 0;
2558 stream->time_position = 0;
2560 stream->n_samples_moof = 0;
2561 stream->duration_moof = 0;
2562 stream->duration_last_moof = 0;
2566 gst_qtdemux_stream_clear (QtDemuxStream * stream)
2569 if (stream->allocator)
2570 gst_object_unref (stream->allocator);
2571 while (stream->buffers) {
2572 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2573 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2575 for (i = 0; i < stream->stsd_entries_length; i++) {
2576 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2577 if (entry->rgb8_palette) {
2578 gst_memory_unref (entry->rgb8_palette);
2579 entry->rgb8_palette = NULL;
2581 entry->sparse = FALSE;
2584 gst_tag_list_unref (stream->stream_tags);
2585 stream->stream_tags = gst_tag_list_new_empty ();
2586 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
2587 g_free (stream->redirect_uri);
2588 stream->redirect_uri = NULL;
2589 stream->sent_eos = FALSE;
2590 stream->protected = FALSE;
2591 if (stream->protection_scheme_info) {
2592 if (stream->protection_scheme_type == FOURCC_cenc) {
2593 QtDemuxCencSampleSetInfo *info =
2594 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2595 if (info->default_properties)
2596 gst_structure_free (info->default_properties);
2597 if (info->crypto_info)
2598 g_ptr_array_free (info->crypto_info, TRUE);
2600 g_free (stream->protection_scheme_info);
2601 stream->protection_scheme_info = NULL;
2603 stream->protection_scheme_type = 0;
2604 stream->protection_scheme_version = 0;
2605 g_queue_foreach (&stream->protection_scheme_event_queue,
2606 (GFunc) gst_event_unref, NULL);
2607 g_queue_clear (&stream->protection_scheme_event_queue);
2608 gst_qtdemux_stream_flush_segments_data (stream);
2609 gst_qtdemux_stream_flush_samples_data (stream);
2613 gst_qtdemux_stream_reset (QtDemuxStream * stream)
2616 gst_qtdemux_stream_clear (stream);
2617 for (i = 0; i < stream->stsd_entries_length; i++) {
2618 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2620 gst_caps_unref (entry->caps);
2624 g_free (stream->stsd_entries);
2625 stream->stsd_entries = NULL;
2626 stream->stsd_entries_length = 0;
2631 gst_qtdemux_stream_free (QtDemuxStream * stream)
2633 gst_qtdemux_stream_reset (stream);
2634 gst_tag_list_unref (stream->stream_tags);
2636 GstQTDemux *demux = stream->demux;
2637 gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
2638 gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
2640 g_free (stream->stream_id);
2645 gst_qtdemux_remove_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
2647 qtdemux->active_streams = g_list_remove (qtdemux->active_streams, stream);
2648 gst_qtdemux_stream_free (stream);
2649 qtdemux->n_streams--;
2652 static GstStateChangeReturn
2653 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2655 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2656 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2658 switch (transition) {
2659 case GST_STATE_CHANGE_PAUSED_TO_READY:
2665 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2667 switch (transition) {
2668 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2669 gst_qtdemux_reset (qtdemux, TRUE);
2680 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2682 /* counts as header data */
2683 qtdemux->header_size += length;
2685 /* only consider at least a sufficiently complete ftyp atom */
2689 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2690 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2691 GST_FOURCC_ARGS (qtdemux->major_brand));
2692 if (qtdemux->comp_brands)
2693 gst_buffer_unref (qtdemux->comp_brands);
2694 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2695 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2700 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist,
2701 GstTagList * xmptaglist)
2703 /* Strip out bogus fields */
2705 if (gst_tag_list_get_scope (taglist) == GST_TAG_SCOPE_GLOBAL) {
2706 gst_tag_list_remove_tag (xmptaglist, GST_TAG_VIDEO_CODEC);
2707 gst_tag_list_remove_tag (xmptaglist, GST_TAG_AUDIO_CODEC);
2709 gst_tag_list_remove_tag (xmptaglist, GST_TAG_CONTAINER_FORMAT);
2712 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, xmptaglist);
2714 /* prioritize native tags using _KEEP mode */
2715 gst_tag_list_insert (taglist, xmptaglist, GST_TAG_MERGE_KEEP);
2716 gst_tag_list_unref (xmptaglist);
2721 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
2729 QtDemuxStream *stream;
2730 GstStructure *structure;
2731 QtDemuxCencSampleSetInfo *ss_info = NULL;
2732 const gchar *system_id;
2733 gboolean uses_sub_sample_encryption = FALSE;
2734 guint32 sample_count;
2736 stream = QTDEMUX_FIRST_STREAM (qtdemux);
2740 structure = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
2741 if (!gst_structure_has_name (structure, "application/x-cenc")) {
2742 GST_WARNING_OBJECT (qtdemux,
2743 "Attempting PIFF box parsing on an unencrypted stream.");
2747 gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
2748 G_TYPE_STRING, &system_id, NULL);
2749 gst_qtdemux_append_protection_system_id (qtdemux, system_id);
2751 stream->protected = TRUE;
2752 stream->protection_scheme_type = FOURCC_cenc;
2754 if (!stream->protection_scheme_info)
2755 stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
2757 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2759 if (ss_info->default_properties)
2760 gst_structure_free (ss_info->default_properties);
2762 ss_info->default_properties =
2763 gst_structure_new ("application/x-cenc",
2764 "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE, NULL);
2766 if (ss_info->crypto_info) {
2767 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
2768 g_ptr_array_free (ss_info->crypto_info, TRUE);
2769 ss_info->crypto_info = NULL;
2773 gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
2775 if (!gst_byte_reader_get_uint8 (&br, &version)) {
2776 GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
2780 if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
2781 GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
2785 if ((flags & 0x000001)) {
2786 guint32 algorithm_id = 0;
2789 gboolean is_encrypted = TRUE;
2791 if (!gst_byte_reader_get_uint24_le (&br, &algorithm_id)) {
2792 GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
2797 if (algorithm_id == 0) {
2798 is_encrypted = FALSE;
2799 } else if (algorithm_id == 1) {
2800 /* FIXME: maybe store this in properties? */
2801 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
2802 } else if (algorithm_id == 2) {
2803 /* FIXME: maybe store this in properties? */
2804 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
2807 if (!gst_byte_reader_get_uint8 (&br, &iv_size))
2810 if (!gst_byte_reader_get_data (&br, 16, &kid))
2813 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
2814 gst_buffer_fill (kid_buf, 0, kid, 16);
2815 if (ss_info->default_properties)
2816 gst_structure_free (ss_info->default_properties);
2817 ss_info->default_properties =
2818 gst_structure_new ("application/x-cenc",
2819 "iv_size", G_TYPE_UINT, iv_size,
2820 "encrypted", G_TYPE_BOOLEAN, is_encrypted,
2821 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
2822 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
2823 "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
2824 gst_buffer_unref (kid_buf);
2825 } else if ((flags & 0x000002)) {
2826 uses_sub_sample_encryption = TRUE;
2829 if (!gst_byte_reader_get_uint32_be (&br, &sample_count)) {
2830 GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
2834 ss_info->crypto_info =
2835 g_ptr_array_new_full (sample_count,
2836 (GDestroyNotify) qtdemux_gst_structure_free);
2838 for (i = 0; i < sample_count; ++i) {
2839 GstStructure *properties;
2843 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
2844 if (properties == NULL) {
2845 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
2846 qtdemux->cenc_aux_sample_count = i;
2850 if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
2851 GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
2852 gst_structure_free (properties);
2853 qtdemux->cenc_aux_sample_count = i;
2856 buf = gst_buffer_new_wrapped (data, iv_size);
2857 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
2858 gst_buffer_unref (buf);
2860 if (uses_sub_sample_encryption) {
2861 guint16 n_subsamples;
2863 if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
2864 || n_subsamples == 0) {
2865 GST_ERROR_OBJECT (qtdemux,
2866 "failed to get subsample count for sample %u", i);
2867 gst_structure_free (properties);
2868 qtdemux->cenc_aux_sample_count = i;
2871 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
2872 if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
2873 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
2875 gst_structure_free (properties);
2876 qtdemux->cenc_aux_sample_count = i;
2879 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
2880 gst_structure_set (properties,
2881 "subsample_count", G_TYPE_UINT, n_subsamples,
2882 "subsamples", GST_TYPE_BUFFER, buf, NULL);
2883 gst_buffer_unref (buf);
2885 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
2888 g_ptr_array_add (ss_info->crypto_info, properties);
2891 qtdemux->cenc_aux_sample_count = sample_count;
2895 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2897 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2898 0x97, 0xA9, 0x42, 0xE8,
2899 0x9C, 0x71, 0x99, 0x94,
2900 0x91, 0xE3, 0xAF, 0xAC
2902 static const guint8 playready_uuid[] = {
2903 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2904 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2907 static const guint8 piff_sample_encryption_uuid[] = {
2908 0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
2909 0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
2914 /* counts as header data */
2915 qtdemux->header_size += length;
2917 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2919 if (length <= offset + 16) {
2920 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2924 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2926 GstTagList *taglist;
2928 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2929 length - offset - 16, NULL);
2930 taglist = gst_tag_list_from_xmp_buffer (buf);
2931 gst_buffer_unref (buf);
2933 /* make sure we have a usable taglist */
2934 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
2936 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
2938 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
2940 const gunichar2 *s_utf16;
2943 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
2944 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
2945 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
2946 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
2950 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
2951 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
2953 } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
2954 qtdemux_parse_piff (qtdemux, buffer, length, offset);
2956 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
2957 GST_READ_UINT32_LE (buffer + offset),
2958 GST_READ_UINT32_LE (buffer + offset + 4),
2959 GST_READ_UINT32_LE (buffer + offset + 8),
2960 GST_READ_UINT32_LE (buffer + offset + 12));
2965 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2967 GstSidxParser sidx_parser;
2968 GstIsoffParserResult res;
2971 gst_isoff_qt_sidx_parser_init (&sidx_parser);
2974 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
2976 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
2977 if (res == GST_ISOFF_QT_PARSER_DONE) {
2978 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
2980 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
2983 /* caller verifies at least 8 bytes in buf */
2985 extract_initial_length_and_fourcc (const guint8 * data, guint size,
2986 guint64 * plength, guint32 * pfourcc)
2991 length = QT_UINT32 (data);
2992 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2993 fourcc = QT_FOURCC (data + 4);
2994 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
2997 length = G_MAXUINT64;
2998 } else if (length == 1 && size >= 16) {
2999 /* this means we have an extended size, which is the 64 bit value of
3000 * the next 8 bytes */
3001 length = QT_UINT64 (data + 8);
3002 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3012 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
3014 guint32 version = 0;
3015 GstClockTime duration = 0;
3017 if (!gst_byte_reader_get_uint32_be (br, &version))
3022 if (!gst_byte_reader_get_uint64_be (br, &duration))
3027 if (!gst_byte_reader_get_uint32_be (br, &dur))
3032 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
3033 qtdemux->duration = duration;
3039 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
3045 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
3046 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
3048 if (!stream->parsed_trex && qtdemux->moov_node) {
3050 GstByteReader trex_data;
3052 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
3054 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
3057 guint32 id = 0, sdi = 0, dur = 0, size = 0, flags = 0;
3059 /* skip version/flags */
3060 if (!gst_byte_reader_skip (&trex_data, 4))
3062 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
3064 if (id != stream->track_id)
3066 if (!gst_byte_reader_get_uint32_be (&trex_data, &sdi))
3068 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
3070 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
3072 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
3075 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
3076 "duration %d, size %d, flags 0x%x", stream->track_id,
3079 stream->parsed_trex = TRUE;
3080 stream->def_sample_description_index = sdi;
3081 stream->def_sample_duration = dur;
3082 stream->def_sample_size = size;
3083 stream->def_sample_flags = flags;
3086 /* iterate all siblings */
3087 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
3093 *ds_duration = stream->def_sample_duration;
3094 *ds_size = stream->def_sample_size;
3095 *ds_flags = stream->def_sample_flags;
3097 /* even then, above values are better than random ... */
3098 if (G_UNLIKELY (!stream->parsed_trex)) {
3099 GST_WARNING_OBJECT (qtdemux,
3100 "failed to find fragment defaults for stream %d", stream->track_id);
3107 /* This method should be called whenever a more accurate duration might
3108 * have been found. It will update all relevant variables if/where needed
3111 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
3115 GstClockTime prevdur;
3118 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
3120 if (movdur > qtdemux->duration) {
3121 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
3122 GST_DEBUG_OBJECT (qtdemux,
3123 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
3124 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
3125 qtdemux->duration = movdur;
3126 GST_DEBUG_OBJECT (qtdemux,
3127 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
3128 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
3129 GST_TIME_ARGS (qtdemux->segment.stop));
3130 if (qtdemux->segment.duration == prevdur) {
3131 /* If the current segment has duration/stop identical to previous duration
3132 * update them also (because they were set at that point in time with
3133 * the wrong duration */
3134 /* We convert the value *from* the timescale version to avoid rounding errors */
3135 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
3136 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
3137 qtdemux->segment.duration = fixeddur;
3138 qtdemux->segment.stop = fixeddur;
3141 for (iter = qtdemux->active_streams, i = 0; iter;
3142 iter = g_list_next (iter), i++) {
3143 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
3145 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
3146 if (movdur > stream->duration) {
3147 GST_DEBUG_OBJECT (qtdemux,
3148 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
3149 GST_TIME_ARGS (duration));
3150 stream->duration = movdur;
3151 /* internal duration tracking state has been updated above, so */
3152 /* preserve an open-ended dummy segment rather than repeatedly updating
3153 * it and spamming downstream accordingly with segment events */
3154 if (stream->dummy_segment &&
3155 GST_CLOCK_TIME_IS_VALID (stream->segments[0].duration)) {
3156 /* Update all dummy values to new duration */
3157 stream->segments[0].stop_time = duration;
3158 stream->segments[0].duration = duration;
3159 stream->segments[0].media_stop = duration;
3161 /* let downstream know we possibly have a new stop time */
3162 if (stream->segment_index != -1) {
3165 if (qtdemux->segment.rate >= 0) {
3166 pos = stream->segment.start;
3168 pos = stream->segment.stop;
3171 gst_qtdemux_stream_update_segment (qtdemux, stream,
3172 stream->segment_index, pos, NULL, NULL);
3180 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
3181 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
3182 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
3183 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts,
3186 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
3188 gint32 data_offset = 0;
3189 guint32 flags = 0, first_flags = 0, samples_count = 0;
3192 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
3193 QtDemuxSample *sample;
3194 gboolean ismv = FALSE;
3195 gint64 initial_offset;
3197 GST_LOG_OBJECT (qtdemux, "parsing trun track-id %d; "
3198 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
3199 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
3200 d_sample_size, d_sample_flags, *base_offset, decode_ts);
3202 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
3203 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
3207 /* presence of stss or not can't really tell us much,
3208 * and flags and so on tend to be marginally reliable in these files */
3209 if (stream->subtype == FOURCC_soun) {
3210 GST_DEBUG_OBJECT (qtdemux,
3211 "sound track in fragmented file; marking all keyframes");
3212 stream->all_keyframe = TRUE;
3215 if (!gst_byte_reader_skip (trun, 1) ||
3216 !gst_byte_reader_get_uint24_be (trun, &flags))
3219 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3222 if (flags & TR_DATA_OFFSET) {
3223 /* note this is really signed */
3224 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3226 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3227 /* default base offset = first byte of moof */
3228 if (*base_offset == -1) {
3229 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3230 *base_offset = moof_offset;
3232 *running_offset = *base_offset + data_offset;
3234 /* if no offset at all, that would mean data starts at moof start,
3235 * which is a bit wrong and is ismv crappy way, so compensate
3236 * assuming data is in mdat following moof */
3237 if (*base_offset == -1) {
3238 *base_offset = moof_offset + moof_length + 8;
3239 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3242 if (*running_offset == -1)
3243 *running_offset = *base_offset;
3246 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3248 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3249 data_offset, flags, samples_count);
3251 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3252 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3253 GST_DEBUG_OBJECT (qtdemux,
3254 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3255 flags ^= TR_FIRST_SAMPLE_FLAGS;
3257 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3259 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3263 /* FIXME ? spec says other bits should also be checked to determine
3264 * entry size (and prefix size for that matter) */
3266 dur_offset = size_offset = 0;
3267 if (flags & TR_SAMPLE_DURATION) {
3268 GST_LOG_OBJECT (qtdemux, "entry duration present");
3269 dur_offset = entry_size;
3272 if (flags & TR_SAMPLE_SIZE) {
3273 GST_LOG_OBJECT (qtdemux, "entry size present");
3274 size_offset = entry_size;
3277 if (flags & TR_SAMPLE_FLAGS) {
3278 GST_LOG_OBJECT (qtdemux, "entry flags present");
3279 flags_offset = entry_size;
3282 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3283 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3284 ct_offset = entry_size;
3288 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3290 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3292 if (stream->n_samples + samples_count >=
3293 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3296 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3297 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3298 (stream->n_samples + samples_count) *
3299 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3301 /* create a new array of samples if it's the first sample parsed */
3302 if (stream->n_samples == 0) {
3303 g_assert (stream->samples == NULL);
3304 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3305 /* or try to reallocate it with space enough to insert the new samples */
3307 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3308 stream->n_samples + samples_count);
3309 if (stream->samples == NULL)
3312 if (qtdemux->fragment_start != -1) {
3313 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3314 qtdemux->fragment_start = -1;
3316 if (stream->n_samples == 0) {
3317 if (decode_ts > 0) {
3318 timestamp = decode_ts;
3319 } else if (stream->pending_seek != NULL) {
3320 /* if we don't have a timestamp from a tfdt box, we'll use the one
3321 * from the mfra seek table */
3322 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3323 GST_TIME_ARGS (stream->pending_seek->ts));
3325 /* FIXME: this is not fully correct, the timestamp refers to the random
3326 * access sample refered to in the tfra entry, which may not necessarily
3327 * be the first sample in the tfrag/trun (but hopefully/usually is) */
3328 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3333 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3334 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3335 GST_TIME_ARGS (gst_ts));
3337 /* subsequent fragments extend stream */
3339 stream->samples[stream->n_samples - 1].timestamp +
3340 stream->samples[stream->n_samples - 1].duration;
3342 /* If this is a GST_FORMAT_BYTES stream and there's a significant
3343 * difference (1 sec.) between decode_ts and timestamp, prefer the
3345 if (has_tfdt && !qtdemux->upstream_format_is_time
3346 && ABSDIFF (decode_ts, timestamp) >
3347 MAX (stream->duration_last_moof / 2,
3348 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) {
3349 GST_INFO_OBJECT (qtdemux,
3350 "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT
3351 ") are significantly different (more than %" GST_TIME_FORMAT
3352 "), using decode_ts",
3353 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)),
3354 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)),
3355 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
3356 MAX (stream->duration_last_moof / 2,
3357 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND)))));
3358 timestamp = decode_ts;
3361 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3362 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3363 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3367 initial_offset = *running_offset;
3369 sample = stream->samples + stream->n_samples;
3370 for (i = 0; i < samples_count; i++) {
3371 guint32 dur, size, sflags, ct;
3373 /* first read sample data */
3374 if (flags & TR_SAMPLE_DURATION) {
3375 dur = QT_UINT32 (data + dur_offset);
3377 dur = d_sample_duration;
3379 if (flags & TR_SAMPLE_SIZE) {
3380 size = QT_UINT32 (data + size_offset);
3382 size = d_sample_size;
3384 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3386 sflags = first_flags;
3388 sflags = d_sample_flags;
3390 } else if (flags & TR_SAMPLE_FLAGS) {
3391 sflags = QT_UINT32 (data + flags_offset);
3393 sflags = d_sample_flags;
3395 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3396 ct = QT_UINT32 (data + ct_offset);
3402 /* fill the sample information */
3403 sample->offset = *running_offset;
3404 sample->pts_offset = ct;
3405 sample->size = size;
3406 sample->timestamp = timestamp;
3407 sample->duration = dur;
3408 /* sample-is-difference-sample */
3409 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3410 * now idea how it relates to bitfield other than massive LE/BE confusion */
3411 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3412 *running_offset += size;
3414 stream->duration_moof += dur;
3418 /* Update total duration if needed */
3419 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3421 /* Pre-emptively figure out size of mdat based on trun information.
3422 * If the [mdat] atom is effectivelly read, it will be replaced by the actual
3423 * size, else we will still be able to use this when dealing with gap'ed
3425 qtdemux->mdatleft = *running_offset - initial_offset;
3426 qtdemux->mdatoffset = initial_offset;
3427 qtdemux->mdatsize = qtdemux->mdatleft;
3429 stream->n_samples += samples_count;
3430 stream->n_samples_moof += samples_count;
3432 if (stream->pending_seek != NULL)
3433 stream->pending_seek = NULL;
3439 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3444 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3450 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3451 "be larger than %uMB (broken file?)", stream->n_samples,
3452 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3457 /* find stream with @id */
3458 static inline QtDemuxStream *
3459 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3461 QtDemuxStream *stream;
3465 if (G_UNLIKELY (!id)) {
3466 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3470 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
3471 stream = QTDEMUX_STREAM (iter->data);
3472 if (stream->track_id == id)
3475 if (qtdemux->mss_mode) {
3476 /* mss should have only 1 stream anyway */
3477 return QTDEMUX_FIRST_STREAM (qtdemux);
3484 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3485 guint32 * fragment_number)
3487 if (!gst_byte_reader_skip (mfhd, 4))
3489 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3494 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3500 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3501 QtDemuxStream ** stream, guint32 * default_sample_duration,
3502 guint32 * default_sample_size, guint32 * default_sample_flags,
3503 gint64 * base_offset)
3506 guint32 track_id = 0;
3508 if (!gst_byte_reader_skip (tfhd, 1) ||
3509 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3512 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3515 *stream = qtdemux_find_stream (qtdemux, track_id);
3516 if (G_UNLIKELY (!*stream))
3517 goto unknown_stream;
3519 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3520 *base_offset = qtdemux->moof_offset;
3522 if (flags & TF_BASE_DATA_OFFSET)
3523 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3526 /* obtain stream defaults */
3527 qtdemux_parse_trex (qtdemux, *stream,
3528 default_sample_duration, default_sample_size, default_sample_flags);
3530 (*stream)->stsd_sample_description_id =
3531 (*stream)->def_sample_description_index - 1;
3533 if (flags & TF_SAMPLE_DESCRIPTION_INDEX) {
3534 guint32 sample_description_index;
3535 if (!gst_byte_reader_get_uint32_be (tfhd, &sample_description_index))
3537 (*stream)->stsd_sample_description_id = sample_description_index - 1;
3540 if (qtdemux->mss_mode) {
3541 /* mss has no stsd entry */
3542 (*stream)->stsd_sample_description_id = 0;
3545 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3546 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3549 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3550 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3553 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3554 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3561 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3566 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
3572 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3573 guint64 * decode_time)
3575 guint32 version = 0;
3577 if (!gst_byte_reader_get_uint32_be (br, &version))
3582 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3585 guint32 dec_time = 0;
3586 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3588 *decode_time = dec_time;
3591 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3598 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3603 /* Returns a pointer to a GstStructure containing the properties of
3604 * the stream sample identified by @sample_index. The caller must unref
3605 * the returned object after use. Returns NULL if unsuccessful. */
3606 static GstStructure *
3607 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3608 QtDemuxStream * stream, guint sample_index)
3610 QtDemuxCencSampleSetInfo *info = NULL;
3612 g_return_val_if_fail (stream != NULL, NULL);
3613 g_return_val_if_fail (stream->protected, NULL);
3614 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3616 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3618 /* Currently, cenc properties for groups of samples are not supported, so
3619 * simply return a copy of the default sample properties */
3620 return gst_structure_copy (info->default_properties);
3623 /* Parses the sizes of sample auxiliary information contained within a stream,
3624 * as given in a saiz box. Returns array of sample_count guint8 size values,
3625 * or NULL on failure */
3627 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3628 GstByteReader * br, guint32 * sample_count)
3632 guint8 default_info_size;
3634 g_return_val_if_fail (qtdemux != NULL, NULL);
3635 g_return_val_if_fail (stream != NULL, NULL);
3636 g_return_val_if_fail (br != NULL, NULL);
3637 g_return_val_if_fail (sample_count != NULL, NULL);
3639 if (!gst_byte_reader_get_uint32_be (br, &flags))
3643 /* aux_info_type and aux_info_type_parameter are ignored */
3644 if (!gst_byte_reader_skip (br, 8))
3648 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3650 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3652 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3654 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3657 if (default_info_size == 0) {
3658 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3662 info_sizes = g_new (guint8, *sample_count);
3663 memset (info_sizes, default_info_size, *sample_count);
3669 /* Parses the offset of sample auxiliary information contained within a stream,
3670 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3672 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3673 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3678 guint32 aux_info_type = 0;
3679 guint32 aux_info_type_parameter = 0;
3680 guint32 entry_count;
3683 const guint8 *aux_info_type_data = NULL;
3685 g_return_val_if_fail (qtdemux != NULL, FALSE);
3686 g_return_val_if_fail (stream != NULL, FALSE);
3687 g_return_val_if_fail (br != NULL, FALSE);
3688 g_return_val_if_fail (offset != NULL, FALSE);
3690 if (!gst_byte_reader_get_uint8 (br, &version))
3693 if (!gst_byte_reader_get_uint24_be (br, &flags))
3698 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3700 aux_info_type = QT_FOURCC (aux_info_type_data);
3702 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3704 } else if (stream->protected) {
3705 aux_info_type = stream->protection_scheme_type;
3707 aux_info_type = CUR_STREAM (stream)->fourcc;
3711 *info_type = aux_info_type;
3712 if (info_type_parameter)
3713 *info_type_parameter = aux_info_type_parameter;
3715 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3716 "aux_info_type_parameter: %#06x",
3717 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3719 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3722 if (entry_count != 1) {
3723 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3728 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3730 *offset = (guint64) off_32;
3732 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3737 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3742 qtdemux_gst_structure_free (GstStructure * gststructure)
3745 gst_structure_free (gststructure);
3749 /* Parses auxiliary information relating to samples protected using Common
3750 * Encryption (cenc); the format of this information is defined in
3751 * ISO/IEC 23001-7. Returns TRUE if successful; FALSE otherwise. */
3753 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3754 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3756 QtDemuxCencSampleSetInfo *ss_info = NULL;
3759 GPtrArray *old_crypto_info = NULL;
3760 guint old_entries = 0;
3762 g_return_val_if_fail (qtdemux != NULL, FALSE);
3763 g_return_val_if_fail (stream != NULL, FALSE);
3764 g_return_val_if_fail (br != NULL, FALSE);
3765 g_return_val_if_fail (stream->protected, FALSE);
3766 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3768 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3770 if (ss_info->crypto_info) {
3771 old_crypto_info = ss_info->crypto_info;
3772 /* Count number of non-null entries remaining at the tail end */
3773 for (i = old_crypto_info->len - 1; i >= 0; i--) {
3774 if (g_ptr_array_index (old_crypto_info, i) == NULL)
3780 ss_info->crypto_info =
3781 g_ptr_array_new_full (sample_count + old_entries,
3782 (GDestroyNotify) qtdemux_gst_structure_free);
3784 /* We preserve old entries because we parse the next moof in advance
3785 * of consuming all samples from the previous moof, and otherwise
3786 * we'd discard the corresponding crypto info for the samples
3787 * from the previous fragment. */
3789 GST_DEBUG_OBJECT (qtdemux, "Preserving %d old crypto info entries",
3791 for (i = old_crypto_info->len - old_entries; i < old_crypto_info->len; i++) {
3792 g_ptr_array_add (ss_info->crypto_info, g_ptr_array_index (old_crypto_info,
3794 g_ptr_array_index (old_crypto_info, i) = NULL;
3798 if (old_crypto_info) {
3799 /* Everything now belongs to the new array */
3800 g_ptr_array_free (old_crypto_info, TRUE);
3803 for (i = 0; i < sample_count; ++i) {
3804 GstStructure *properties;
3805 guint16 n_subsamples = 0;
3810 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3811 if (properties == NULL) {
3812 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3815 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3816 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3817 gst_structure_free (properties);
3820 if (!gst_byte_reader_dup_data (br, iv_size, &data)) {
3821 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3822 gst_structure_free (properties);
3825 buf = gst_buffer_new_wrapped (data, iv_size);
3826 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3827 gst_buffer_unref (buf);
3828 size = info_sizes[i];
3829 if (size > iv_size) {
3830 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3831 || !(n_subsamples > 0)) {
3832 gst_structure_free (properties);
3833 GST_ERROR_OBJECT (qtdemux,
3834 "failed to get subsample count for sample %u", i);
3837 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3838 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3839 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3841 gst_structure_free (properties);
3844 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3846 gst_structure_free (properties);
3849 gst_structure_set (properties,
3850 "subsample_count", G_TYPE_UINT, n_subsamples,
3851 "subsamples", GST_TYPE_BUFFER, buf, NULL);
3852 gst_buffer_unref (buf);
3854 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3856 g_ptr_array_add (ss_info->crypto_info, properties);
3861 /* Converts a UUID in raw byte form to a string representation, as defined in
3862 * RFC 4122. The caller takes ownership of the returned string and is
3863 * responsible for freeing it after use. */
3865 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3867 const guint8 *uuid = (const guint8 *) uuid_bytes;
3869 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3870 "%02x%02x-%02x%02x%02x%02x%02x%02x",
3871 uuid[0], uuid[1], uuid[2], uuid[3],
3872 uuid[4], uuid[5], uuid[6], uuid[7],
3873 uuid[8], uuid[9], uuid[10], uuid[11],
3874 uuid[12], uuid[13], uuid[14], uuid[15]);
3877 /* Parses a Protection System Specific Header box (pssh), as defined in the
3878 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3879 * information needed by a specific content protection system in order to
3880 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3883 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
3885 gchar *sysid_string;
3886 guint32 pssh_size = QT_UINT32 (node->data);
3887 GstBuffer *pssh = NULL;
3888 GstEvent *event = NULL;
3889 guint32 parent_box_type;
3892 if (G_UNLIKELY (pssh_size < 32U)) {
3893 GST_ERROR_OBJECT (qtdemux, "invalid box size");
3898 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
3900 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
3902 pssh = gst_buffer_new_wrapped (g_memdup (node->data, pssh_size), pssh_size);
3903 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
3904 gst_buffer_get_size (pssh));
3906 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
3908 /* Push an event containing the pssh box onto the queues of all streams. */
3909 event = gst_event_new_protection (sysid_string, pssh,
3910 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
3911 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
3912 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
3913 g_queue_push_tail (&stream->protection_scheme_event_queue,
3914 gst_event_ref (event));
3916 g_free (sysid_string);
3917 gst_event_unref (event);
3918 gst_buffer_unref (pssh);
3923 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
3924 guint64 moof_offset, QtDemuxStream * stream)
3926 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
3928 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
3929 GNode *saiz_node, *saio_node, *pssh_node;
3930 GstByteReader saiz_data, saio_data;
3931 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
3932 gint64 base_offset, running_offset;
3935 /* NOTE @stream ignored */
3937 moof_node = g_node_new ((guint8 *) buffer);
3938 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
3939 qtdemux_node_dump (qtdemux, moof_node);
3941 /* Get fragment number from mfhd and check it's valid */
3943 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
3944 if (mfhd_node == NULL)
3946 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
3948 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
3950 /* unknown base_offset to start with */
3951 base_offset = running_offset = -1;
3952 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
3954 guint64 decode_time = 0;
3956 /* Fragment Header node */
3958 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
3962 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
3963 &ds_size, &ds_flags, &base_offset))
3966 /* The following code assumes at most a single set of sample auxiliary
3967 * data in the fragment (consisting of a saiz box and a corresponding saio
3968 * box); in theory, however, there could be multiple sets of sample
3969 * auxiliary data in a fragment. */
3971 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
3974 guint32 info_type = 0;
3976 guint32 info_type_parameter = 0;
3978 g_free (qtdemux->cenc_aux_info_sizes);
3980 qtdemux->cenc_aux_info_sizes =
3981 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
3982 &qtdemux->cenc_aux_sample_count);
3983 if (qtdemux->cenc_aux_info_sizes == NULL) {
3984 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
3988 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
3991 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
3992 g_free (qtdemux->cenc_aux_info_sizes);
3993 qtdemux->cenc_aux_info_sizes = NULL;
3997 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
3998 &info_type, &info_type_parameter, &offset))) {
3999 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
4000 g_free (qtdemux->cenc_aux_info_sizes);
4001 qtdemux->cenc_aux_info_sizes = NULL;
4004 if (base_offset > -1 && base_offset > qtdemux->moof_offset)
4005 offset += (guint64) (base_offset - qtdemux->moof_offset);
4006 if (info_type == FOURCC_cenc && info_type_parameter == 0U) {
4008 if (offset > length) {
4009 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
4010 qtdemux->cenc_aux_info_offset = offset;
4012 gst_byte_reader_init (&br, buffer + offset, length - offset);
4013 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
4014 qtdemux->cenc_aux_info_sizes,
4015 qtdemux->cenc_aux_sample_count)) {
4016 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
4017 g_free (qtdemux->cenc_aux_info_sizes);
4018 qtdemux->cenc_aux_info_sizes = NULL;
4026 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
4029 /* We'll use decode_time to interpolate timestamps
4030 * in case the input timestamps are missing */
4031 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
4033 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
4034 " (%" GST_TIME_FORMAT ")", decode_time,
4035 GST_TIME_ARGS (stream ? QTSTREAMTIME_TO_GSTTIME (stream,
4036 decode_time) : GST_CLOCK_TIME_NONE));
4038 /* Discard the fragment buffer timestamp info to avoid using it.
4039 * Rely on tfdt instead as it is more accurate than the timestamp
4040 * that is fetched from a manifest/playlist and is usually
4042 qtdemux->fragment_start = -1;
4045 if (G_UNLIKELY (!stream)) {
4046 /* we lost track of offset, we'll need to regain it,
4047 * but can delay complaining until later or avoid doing so altogether */
4051 if (G_UNLIKELY (base_offset < -1))
4054 if (qtdemux->upstream_format_is_time)
4055 gst_qtdemux_stream_flush_samples_data (stream);
4057 /* initialise moof sample data */
4058 stream->n_samples_moof = 0;
4059 stream->duration_last_moof = stream->duration_moof;
4060 stream->duration_moof = 0;
4062 /* Track Run node */
4064 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
4067 qtdemux_parse_trun (qtdemux, &trun_data, stream,
4068 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
4069 &running_offset, decode_time, (tfdt_node != NULL));
4070 /* iterate all siblings */
4071 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
4075 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
4077 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
4078 guint32 box_length = QT_UINT32 (uuid_buffer);
4080 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
4083 /* if no new base_offset provided for next traf,
4084 * base is end of current traf */
4085 base_offset = running_offset;
4086 running_offset = -1;
4088 if (stream->n_samples_moof && stream->duration_moof)
4089 stream->new_caps = TRUE;
4092 /* iterate all siblings */
4093 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
4096 /* parse any protection system info */
4097 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
4099 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
4100 qtdemux_parse_pssh (qtdemux, pssh_node);
4101 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
4104 g_node_destroy (moof_node);
4109 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
4114 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
4119 GST_DEBUG_OBJECT (qtdemux, "lost offset");
4124 g_node_destroy (moof_node);
4125 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4126 (_("This file is corrupt and cannot be played.")), (NULL));
4132 /* might be used if some day we actually use mfra & co
4133 * for random access to fragments,
4134 * but that will require quite some modifications and much less relying
4135 * on a sample array */
4139 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
4141 QtDemuxStream *stream;
4142 guint32 ver_flags, track_id, len, num_entries, i;
4143 guint value_size, traf_size, trun_size, sample_size;
4144 guint64 time = 0, moof_offset = 0;
4146 GstBuffer *buf = NULL;
4151 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
4153 if (!gst_byte_reader_skip (&tfra, 8))
4156 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
4159 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
4160 || !gst_byte_reader_get_uint32_be (&tfra, &len)
4161 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
4164 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
4166 stream = qtdemux_find_stream (qtdemux, track_id);
4168 goto unknown_trackid;
4170 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
4171 sample_size = (len & 3) + 1;
4172 trun_size = ((len & 12) >> 2) + 1;
4173 traf_size = ((len & 48) >> 4) + 1;
4175 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
4176 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
4178 if (num_entries == 0)
4181 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
4182 value_size + value_size + traf_size + trun_size + sample_size))
4185 g_free (stream->ra_entries);
4186 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
4187 stream->n_ra_entries = num_entries;
4189 for (i = 0; i < num_entries; i++) {
4190 qt_atom_parser_get_offset (&tfra, value_size, &time);
4191 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
4192 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
4193 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
4194 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
4196 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
4198 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
4199 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
4201 stream->ra_entries[i].ts = time;
4202 stream->ra_entries[i].moof_offset = moof_offset;
4204 /* don't want to go through the entire file and read all moofs at startup */
4206 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
4207 if (ret != GST_FLOW_OK)
4209 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
4210 moof_offset, stream);
4211 gst_buffer_unref (buf);
4215 check_update_duration (qtdemux, time);
4222 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
4227 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
4232 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4238 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
4240 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
4241 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
4242 GstBuffer *mfro = NULL, *mfra = NULL;
4244 gboolean ret = FALSE;
4245 GNode *mfra_node, *tfra_node;
4246 guint64 mfra_offset = 0;
4247 guint32 fourcc, mfra_size;
4250 /* query upstream size in bytes */
4251 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4252 goto size_query_failed;
4254 /* mfro box should be at the very end of the file */
4255 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4256 if (flow != GST_FLOW_OK)
4259 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4261 fourcc = QT_FOURCC (mfro_map.data + 4);
4262 if (fourcc != FOURCC_mfro)
4265 GST_INFO_OBJECT (qtdemux, "Found mfro box");
4266 if (mfro_map.size < 16)
4267 goto invalid_mfro_size;
4269 mfra_size = QT_UINT32 (mfro_map.data + 12);
4270 if (mfra_size >= len)
4271 goto invalid_mfra_size;
4273 mfra_offset = len - mfra_size;
4275 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4276 mfra_offset, mfra_size);
4278 /* now get and parse mfra box */
4279 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4280 if (flow != GST_FLOW_OK)
4283 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4285 mfra_node = g_node_new ((guint8 *) mfra_map.data);
4286 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4288 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4291 qtdemux_parse_tfra (qtdemux, tfra_node);
4292 /* iterate all siblings */
4293 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4295 g_node_destroy (mfra_node);
4297 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4303 if (mfro_map.memory != NULL)
4304 gst_buffer_unmap (mfro, &mfro_map);
4305 gst_buffer_unref (mfro);
4308 if (mfra_map.memory != NULL)
4309 gst_buffer_unmap (mfra, &mfra_map);
4310 gst_buffer_unref (mfra);
4317 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4322 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4327 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4332 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4338 add_offset (guint64 offset, guint64 advance)
4340 /* Avoid 64-bit overflow by clamping */
4341 if (offset > G_MAXUINT64 - advance)
4343 return offset + advance;
4346 static GstFlowReturn
4347 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4351 GstBuffer *buf = NULL;
4352 GstFlowReturn ret = GST_FLOW_OK;
4353 guint64 cur_offset = qtdemux->offset;
4356 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4357 if (G_UNLIKELY (ret != GST_FLOW_OK))
4359 gst_buffer_map (buf, &map, GST_MAP_READ);
4360 if (G_LIKELY (map.size >= 8))
4361 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4362 gst_buffer_unmap (buf, &map);
4363 gst_buffer_unref (buf);
4365 /* maybe we already got most we needed, so only consider this eof */
4366 if (G_UNLIKELY (length == 0)) {
4367 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4368 (_("Invalid atom size.")),
4369 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4370 GST_FOURCC_ARGS (fourcc)));
4377 /* record for later parsing when needed */
4378 if (!qtdemux->moof_offset) {
4379 qtdemux->moof_offset = qtdemux->offset;
4381 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4384 qtdemux->offset += length; /* skip moof and keep going */
4386 if (qtdemux->got_moov) {
4387 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4399 GST_LOG_OBJECT (qtdemux,
4400 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4401 GST_FOURCC_ARGS (fourcc), cur_offset);
4402 qtdemux->offset = add_offset (qtdemux->offset, length);
4407 GstBuffer *moov = NULL;
4409 if (qtdemux->got_moov) {
4410 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4411 qtdemux->offset = add_offset (qtdemux->offset, length);
4415 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4416 if (ret != GST_FLOW_OK)
4418 gst_buffer_map (moov, &map, GST_MAP_READ);
4420 if (length != map.size) {
4421 /* Some files have a 'moov' atom at the end of the file which contains
4422 * a terminal 'free' atom where the body of the atom is missing.
4423 * Check for, and permit, this special case.
4425 if (map.size >= 8) {
4426 guint8 *final_data = map.data + (map.size - 8);
4427 guint32 final_length = QT_UINT32 (final_data);
4428 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4430 if (final_fourcc == FOURCC_free
4431 && map.size + final_length - 8 == length) {
4432 /* Ok, we've found that special case. Allocate a new buffer with
4433 * that free atom actually present. */
4434 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4435 gst_buffer_fill (newmoov, 0, map.data, map.size);
4436 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4437 gst_buffer_unmap (moov, &map);
4438 gst_buffer_unref (moov);
4440 gst_buffer_map (moov, &map, GST_MAP_READ);
4445 if (length != map.size) {
4446 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4447 (_("This file is incomplete and cannot be played.")),
4448 ("We got less than expected (received %" G_GSIZE_FORMAT
4449 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4450 (guint) length, cur_offset));
4451 gst_buffer_unmap (moov, &map);
4452 gst_buffer_unref (moov);
4453 ret = GST_FLOW_ERROR;
4456 qtdemux->offset += length;
4458 qtdemux_parse_moov (qtdemux, map.data, length);
4459 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4461 qtdemux_parse_tree (qtdemux);
4462 if (qtdemux->moov_node_compressed) {
4463 g_node_destroy (qtdemux->moov_node_compressed);
4464 g_free (qtdemux->moov_node->data);
4466 qtdemux->moov_node_compressed = NULL;
4467 g_node_destroy (qtdemux->moov_node);
4468 qtdemux->moov_node = NULL;
4469 gst_buffer_unmap (moov, &map);
4470 gst_buffer_unref (moov);
4471 qtdemux->got_moov = TRUE;
4477 GstBuffer *ftyp = NULL;
4479 /* extract major brand; might come in handy for ISO vs QT issues */
4480 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4481 if (ret != GST_FLOW_OK)
4483 qtdemux->offset += length;
4484 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4485 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4486 gst_buffer_unmap (ftyp, &map);
4487 gst_buffer_unref (ftyp);
4492 GstBuffer *uuid = NULL;
4494 /* uuid are extension atoms */
4495 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4496 if (ret != GST_FLOW_OK)
4498 qtdemux->offset += length;
4499 gst_buffer_map (uuid, &map, GST_MAP_READ);
4500 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4501 gst_buffer_unmap (uuid, &map);
4502 gst_buffer_unref (uuid);
4507 GstBuffer *sidx = NULL;
4508 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4509 if (ret != GST_FLOW_OK)
4511 qtdemux->offset += length;
4512 gst_buffer_map (sidx, &map, GST_MAP_READ);
4513 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4514 gst_buffer_unmap (sidx, &map);
4515 gst_buffer_unref (sidx);
4520 GstBuffer *unknown = NULL;
4522 GST_LOG_OBJECT (qtdemux,
4523 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4524 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4526 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4527 if (ret != GST_FLOW_OK)
4529 gst_buffer_map (unknown, &map, GST_MAP_READ);
4530 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4531 gst_buffer_unmap (unknown, &map);
4532 gst_buffer_unref (unknown);
4533 qtdemux->offset += length;
4539 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4540 /* digested all data, show what we have */
4541 qtdemux_prepare_streams (qtdemux);
4542 ret = qtdemux_expose_streams (qtdemux);
4544 qtdemux->state = QTDEMUX_STATE_MOVIE;
4545 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4552 /* Seeks to the previous keyframe of the indexed stream and
4553 * aligns other streams with respect to the keyframe timestamp
4554 * of indexed stream. Only called in case of Reverse Playback
4556 static GstFlowReturn
4557 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4559 guint32 seg_idx = 0, k_index = 0;
4560 guint32 ref_seg_idx, ref_k_index;
4561 GstClockTime k_pos = 0, last_stop = 0;
4562 QtDemuxSegment *seg = NULL;
4563 QtDemuxStream *ref_str = NULL;
4564 guint64 seg_media_start_mov; /* segment media start time in mov format */
4568 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4569 * and finally align all the other streams on that timestamp with their
4570 * respective keyframes */
4571 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
4572 QtDemuxStream *str = QTDEMUX_STREAM (iter->data);
4574 /* No candidate yet, take the first stream */
4580 /* So that stream has a segment, we prefer video streams */
4581 if (str->subtype == FOURCC_vide) {
4587 if (G_UNLIKELY (!ref_str)) {
4588 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4592 if (G_UNLIKELY (!ref_str->from_sample)) {
4593 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4597 /* So that stream has been playing from from_sample to to_sample. We will
4598 * get the timestamp of the previous sample and search for a keyframe before
4599 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4600 if (ref_str->subtype == FOURCC_vide) {
4601 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4602 ref_str->from_sample - 1, FALSE);
4604 if (ref_str->from_sample >= 10)
4605 k_index = ref_str->from_sample - 10;
4611 ref_str->samples[k_index].timestamp +
4612 ref_str->samples[k_index].pts_offset;
4614 /* get current segment for that stream */
4615 seg = &ref_str->segments[ref_str->segment_index];
4616 /* Use segment start in original timescale for comparisons */
4617 seg_media_start_mov = seg->trak_media_start;
4619 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4620 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT "\n",
4621 k_index, target_ts, seg_media_start_mov,
4622 GST_TIME_ARGS (seg->media_start));
4624 /* Crawl back through segments to find the one containing this I frame */
4625 while (target_ts < seg_media_start_mov) {
4626 GST_DEBUG_OBJECT (qtdemux,
4627 "keyframe position (sample %u) is out of segment %u " " target %"
4628 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4629 ref_str->segment_index, target_ts, seg_media_start_mov);
4631 if (G_UNLIKELY (!ref_str->segment_index)) {
4632 /* Reached first segment, let's consider it's EOS */
4635 ref_str->segment_index--;
4636 seg = &ref_str->segments[ref_str->segment_index];
4637 /* Use segment start in original timescale for comparisons */
4638 seg_media_start_mov = seg->trak_media_start;
4640 /* Calculate time position of the keyframe and where we should stop */
4642 QTSTREAMTIME_TO_GSTTIME (ref_str,
4643 target_ts - seg->trak_media_start) + seg->time;
4645 QTSTREAMTIME_TO_GSTTIME (ref_str,
4646 ref_str->samples[ref_str->from_sample].timestamp -
4647 seg->trak_media_start) + seg->time;
4649 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4650 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4651 k_index, GST_TIME_ARGS (k_pos));
4653 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4654 qtdemux->segment.position = last_stop;
4655 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4656 GST_TIME_ARGS (last_stop));
4658 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4659 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4663 ref_seg_idx = ref_str->segment_index;
4664 ref_k_index = k_index;
4666 /* Align them all on this */
4667 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
4669 GstClockTime seg_time = 0;
4670 QtDemuxStream *str = QTDEMUX_STREAM (iter->data);
4672 /* aligning reference stream again might lead to backing up to yet another
4673 * keyframe (due to timestamp rounding issues),
4674 * potentially putting more load on downstream; so let's try to avoid */
4675 if (str == ref_str) {
4676 seg_idx = ref_seg_idx;
4677 seg = &str->segments[seg_idx];
4678 k_index = ref_k_index;
4679 GST_DEBUG_OBJECT (qtdemux, "reference track-id %u segment %d, "
4680 "sample at index %d", str->track_id, ref_str->segment_index, k_index);
4682 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4683 GST_DEBUG_OBJECT (qtdemux,
4684 "track-id %u align segment %d for keyframe pos %" GST_TIME_FORMAT,
4685 str->track_id, seg_idx, GST_TIME_ARGS (k_pos));
4687 /* get segment and time in the segment */
4688 seg = &str->segments[seg_idx];
4689 seg_time = k_pos - seg->time;
4691 /* get the media time in the segment.
4692 * No adjustment for empty "filler" segments */
4693 if (seg->media_start != GST_CLOCK_TIME_NONE)
4694 seg_time += seg->media_start;
4696 /* get the index of the sample with media time */
4697 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4698 GST_DEBUG_OBJECT (qtdemux,
4699 "track-id %u sample for %" GST_TIME_FORMAT " at %u", str->track_id,
4700 GST_TIME_ARGS (seg_time), index);
4702 /* find previous keyframe */
4703 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
4706 /* Remember until where we want to go */
4707 str->to_sample = str->from_sample - 1;
4708 /* Define our time position */
4710 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4711 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4712 if (seg->media_start != GST_CLOCK_TIME_NONE)
4713 str->time_position -= seg->media_start;
4715 /* Now seek back in time */
4716 gst_qtdemux_move_stream (qtdemux, str, k_index);
4717 GST_DEBUG_OBJECT (qtdemux, "track-id %u keyframe at %u, time position %"
4718 GST_TIME_FORMAT " playing from sample %u to %u", str->track_id, k_index,
4719 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4725 return GST_FLOW_EOS;
4729 * Gets the current qt segment start, stop and position for the
4730 * given time offset. This is used in update_segment()
4733 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
4734 QtDemuxStream * stream, GstClockTime offset,
4735 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
4737 GstClockTime seg_time;
4738 GstClockTime start, stop, time;
4739 QtDemuxSegment *segment;
4741 segment = &stream->segments[stream->segment_index];
4743 /* get time in this segment */
4744 seg_time = (offset - segment->time) * segment->rate;
4746 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4747 GST_TIME_ARGS (seg_time));
4749 if (G_UNLIKELY (seg_time > segment->duration)) {
4750 GST_LOG_OBJECT (stream->pad,
4751 "seg_time > segment->duration %" GST_TIME_FORMAT,
4752 GST_TIME_ARGS (segment->duration));
4753 seg_time = segment->duration;
4756 /* qtdemux->segment.stop is in outside-time-realm, whereas
4757 * segment->media_stop is in track-time-realm.
4759 * In order to compare the two, we need to bring segment.stop
4760 * into the track-time-realm
4762 * FIXME - does this comment still hold? Don't see any conversion here */
4764 stop = qtdemux->segment.stop;
4765 if (stop == GST_CLOCK_TIME_NONE)
4766 stop = qtdemux->segment.duration;
4767 if (stop == GST_CLOCK_TIME_NONE)
4768 stop = segment->media_stop;
4771 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4773 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4774 start = segment->time + seg_time;
4776 stop = start - seg_time + segment->duration;
4777 } else if (qtdemux->segment.rate >= 0) {
4778 start = MIN (segment->media_start + seg_time, stop);
4781 if (segment->media_start >= qtdemux->segment.start) {
4782 time = segment->time;
4784 time = segment->time + (qtdemux->segment.start - segment->media_start);
4787 start = MAX (segment->media_start, qtdemux->segment.start);
4788 stop = MIN (segment->media_start + seg_time, stop);
4797 * Updates the qt segment used for the stream and pushes a new segment event
4798 * downstream on this stream's pad.
4801 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4802 gint seg_idx, GstClockTime offset, GstClockTime * _start,
4803 GstClockTime * _stop)
4805 QtDemuxSegment *segment;
4806 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
4810 /* update the current segment */
4811 stream->segment_index = seg_idx;
4813 /* get the segment */
4814 segment = &stream->segments[seg_idx];
4816 if (G_UNLIKELY (offset < segment->time)) {
4817 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4818 GST_TIME_ARGS (segment->time));
4822 /* segment lies beyond total indicated duration */
4823 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4824 segment->time > qtdemux->segment.duration)) {
4825 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4826 " < segment->time %" GST_TIME_FORMAT,
4827 GST_TIME_ARGS (qtdemux->segment.duration),
4828 GST_TIME_ARGS (segment->time));
4832 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
4833 &start, &stop, &time);
4835 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
4836 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
4837 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
4839 /* combine global rate with that of the segment */
4840 rate = segment->rate * qtdemux->segment.rate;
4842 /* Copy flags from main segment */
4843 stream->segment.flags = qtdemux->segment.flags;
4845 /* update the segment values used for clipping */
4846 stream->segment.offset = qtdemux->segment.offset;
4847 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
4848 stream->segment.applied_rate = qtdemux->segment.applied_rate;
4849 stream->segment.rate = rate;
4850 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
4851 stream->cslg_shift);
4852 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
4853 stream->cslg_shift);
4854 stream->segment.time = time;
4855 stream->segment.position = stream->segment.start;
4857 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
4860 /* now prepare and send the segment */
4862 event = gst_event_new_segment (&stream->segment);
4863 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
4864 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
4866 gst_pad_push_event (stream->pad, event);
4867 /* assume we can send more data now */
4868 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
4869 /* clear to send tags on this pad now */
4870 gst_qtdemux_push_tags (qtdemux, stream);
4881 /* activate the given segment number @seg_idx of @stream at time @offset.
4882 * @offset is an absolute global position over all the segments.
4884 * This will push out a NEWSEGMENT event with the right values and
4885 * position the stream index to the first decodable sample before
4889 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4890 guint32 seg_idx, GstClockTime offset)
4892 QtDemuxSegment *segment;
4893 guint32 index, kf_index;
4894 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
4896 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
4897 seg_idx, GST_TIME_ARGS (offset));
4899 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
4903 segment = &stream->segments[stream->segment_index];
4905 /* in the fragmented case, we pick a fragment that starts before our
4906 * desired position and rely on downstream to wait for a keyframe
4907 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
4908 * tfra entries tells us which trun/sample the key unit is in, but we don't
4909 * make use of this additional information at the moment) */
4910 if (qtdemux->fragmented && !qtdemux->fragmented_seek_pending) {
4911 stream->to_sample = G_MAXUINT32;
4914 /* well, it will be taken care of below */
4915 qtdemux->fragmented_seek_pending = FALSE;
4916 /* FIXME ideally the do_fragmented_seek can be done right here,
4917 * rather than at loop level
4918 * (which might even allow handling edit lists in a fragmented file) */
4921 /* We don't need to look for a sample in push-based */
4922 if (!qtdemux->pullbased)
4925 /* and move to the keyframe before the indicated media time of the
4927 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
4928 if (qtdemux->segment.rate >= 0) {
4929 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
4930 stream->to_sample = G_MAXUINT32;
4931 GST_DEBUG_OBJECT (stream->pad,
4932 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4933 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
4934 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4936 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
4937 stream->to_sample = index;
4938 GST_DEBUG_OBJECT (stream->pad,
4939 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4940 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
4941 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4944 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
4945 "this is an empty segment");
4949 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
4950 * encountered an error and printed a message so we return appropriately */
4954 /* we're at the right spot */
4955 if (index == stream->sample_index) {
4956 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
4960 /* find keyframe of the target index */
4961 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
4964 /* indent does stupid stuff with stream->samples[].timestamp */
4966 /* if we move forwards, we don't have to go back to the previous
4967 * keyframe since we already sent that. We can also just jump to
4968 * the keyframe right before the target index if there is one. */
4969 if (index > stream->sample_index) {
4970 /* moving forwards check if we move past a keyframe */
4971 if (kf_index > stream->sample_index) {
4972 GST_DEBUG_OBJECT (stream->pad,
4973 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4974 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4975 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4976 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4978 GST_DEBUG_OBJECT (stream->pad,
4979 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
4980 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
4981 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
4984 GST_DEBUG_OBJECT (stream->pad,
4985 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4986 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4987 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4988 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4996 /* prepare to get the current sample of @stream, getting essential values.
4998 * This function will also prepare and send the segment when needed.
5000 * Return FALSE if the stream is EOS.
5005 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
5006 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
5007 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
5008 gboolean * keyframe)
5010 QtDemuxSample *sample;
5011 GstClockTime time_position;
5014 g_return_val_if_fail (stream != NULL, FALSE);
5016 time_position = stream->time_position;
5017 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
5020 seg_idx = stream->segment_index;
5021 if (G_UNLIKELY (seg_idx == -1)) {
5022 /* find segment corresponding to time_position if we are looking
5024 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
5027 /* different segment, activate it, sample_index will be set. */
5028 if (G_UNLIKELY (stream->segment_index != seg_idx))
5029 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
5031 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->segments[stream->
5033 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
5035 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
5036 " prepare empty sample");
5039 *pts = *dts = time_position;
5040 *duration = seg->duration - (time_position - seg->time);
5047 if (stream->sample_index == -1)
5048 stream->sample_index = 0;
5050 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
5051 stream->sample_index, stream->n_samples);
5053 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
5054 if (!qtdemux->fragmented)
5057 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
5061 GST_OBJECT_LOCK (qtdemux);
5062 flow = qtdemux_add_fragmented_samples (qtdemux);
5063 GST_OBJECT_UNLOCK (qtdemux);
5065 if (flow != GST_FLOW_OK)
5068 while (stream->sample_index >= stream->n_samples);
5071 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5072 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5073 stream->sample_index);
5077 /* now get the info for the sample we're at */
5078 sample = &stream->samples[stream->sample_index];
5080 *dts = QTSAMPLE_DTS (stream, sample);
5081 *pts = QTSAMPLE_PTS (stream, sample);
5082 *offset = sample->offset;
5083 *size = sample->size;
5084 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
5085 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5092 stream->time_position = GST_CLOCK_TIME_NONE;
5097 /* move to the next sample in @stream.
5099 * Moves to the next segment when needed.
5102 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
5104 QtDemuxSample *sample;
5105 QtDemuxSegment *segment;
5107 /* get current segment */
5108 segment = &stream->segments[stream->segment_index];
5110 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5111 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
5115 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
5116 /* Mark the stream as EOS */
5117 GST_DEBUG_OBJECT (qtdemux,
5118 "reached max allowed sample %u, mark EOS", stream->to_sample);
5119 stream->time_position = GST_CLOCK_TIME_NONE;
5123 /* move to next sample */
5124 stream->sample_index++;
5125 stream->offset_in_sample = 0;
5127 /* reached the last sample, we need the next segment */
5128 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
5131 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5132 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5133 stream->sample_index);
5137 /* get next sample */
5138 sample = &stream->samples[stream->sample_index];
5140 /* see if we are past the segment */
5141 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
5144 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
5145 /* inside the segment, update time_position, looks very familiar to
5146 * GStreamer segments, doesn't it? */
5147 stream->time_position =
5148 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
5150 /* not yet in segment, time does not yet increment. This means
5151 * that we are still prerolling keyframes to the decoder so it can
5152 * decode the first sample of the segment. */
5153 stream->time_position = segment->time;
5157 /* move to the next segment */
5160 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
5162 if (stream->segment_index == stream->n_segments - 1) {
5163 /* are we at the end of the last segment, we're EOS */
5164 stream->time_position = GST_CLOCK_TIME_NONE;
5166 /* else we're only at the end of the current segment */
5167 stream->time_position = segment->stop_time;
5169 /* make sure we select a new segment */
5171 /* accumulate previous segments */
5172 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
5173 stream->accumulated_base +=
5174 (stream->segment.stop -
5175 stream->segment.start) / ABS (stream->segment.rate);
5177 stream->segment_index = -1;
5182 gst_qtdemux_sync_streams (GstQTDemux * demux)
5186 if (demux->n_streams <= 1)
5189 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
5190 QtDemuxStream *stream;
5191 GstClockTime end_time;
5193 stream = QTDEMUX_STREAM (iter->data);
5198 /* TODO advance time on subtitle streams here, if any some day */
5200 /* some clips/trailers may have unbalanced streams at the end,
5201 * so send EOS on shorter stream to prevent stalling others */
5203 /* do not mess with EOS if SEGMENT seeking */
5204 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5207 if (demux->pullbased) {
5208 /* loop mode is sample time based */
5209 if (!STREAM_IS_EOS (stream))
5212 /* push mode is byte position based */
5213 if (stream->n_samples &&
5214 stream->samples[stream->n_samples - 1].offset >= demux->offset)
5218 if (stream->sent_eos)
5221 /* only act if some gap */
5222 end_time = stream->segments[stream->n_segments - 1].stop_time;
5223 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5224 ", stream end: %" GST_TIME_FORMAT,
5225 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5226 if (GST_CLOCK_TIME_IS_VALID (end_time)
5227 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5230 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5231 GST_PAD_NAME (stream->pad));
5232 stream->sent_eos = TRUE;
5233 event = gst_event_new_eos ();
5234 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
5235 gst_event_set_seqnum (event, demux->segment_seqnum);
5236 gst_pad_push_event (stream->pad, event);
5241 /* EOS and NOT_LINKED need to be combined. This means that we return:
5243 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
5244 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
5246 static GstFlowReturn
5247 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
5250 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
5253 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5256 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5258 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5262 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5263 * completely clipped
5265 * Should be used only with raw buffers */
5267 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5270 guint64 start, stop, cstart, cstop, diff;
5271 GstClockTime pts, duration;
5273 gint num_rate, denom_rate;
5278 osize = size = gst_buffer_get_size (buf);
5281 /* depending on the type, setup the clip parameters */
5282 if (stream->subtype == FOURCC_soun) {
5283 frame_size = CUR_STREAM (stream)->bytes_per_frame;
5284 num_rate = GST_SECOND;
5285 denom_rate = (gint) CUR_STREAM (stream)->rate;
5287 } else if (stream->subtype == FOURCC_vide) {
5289 num_rate = CUR_STREAM (stream)->fps_n;
5290 denom_rate = CUR_STREAM (stream)->fps_d;
5295 if (frame_size <= 0)
5296 goto bad_frame_size;
5298 /* we can only clip if we have a valid pts */
5299 pts = GST_BUFFER_PTS (buf);
5300 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5303 duration = GST_BUFFER_DURATION (buf);
5305 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5307 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5311 stop = start + duration;
5313 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5314 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5317 /* see if some clipping happened */
5318 diff = cstart - start;
5324 /* bring clipped time to samples and to bytes */
5325 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5328 GST_DEBUG_OBJECT (qtdemux,
5329 "clipping start to %" GST_TIME_FORMAT " %"
5330 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5336 diff = stop - cstop;
5341 /* bring clipped time to samples and then to bytes */
5342 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5344 GST_DEBUG_OBJECT (qtdemux,
5345 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5346 " bytes", GST_TIME_ARGS (cstop), diff);
5351 if (offset != 0 || size != osize)
5352 gst_buffer_resize (buf, offset, size);
5354 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5355 GST_BUFFER_PTS (buf) = pts;
5356 GST_BUFFER_DURATION (buf) = duration;
5360 /* dropped buffer */
5363 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5368 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5373 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5378 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5379 gst_buffer_unref (buf);
5385 gst_qtdemux_align_buffer (GstQTDemux * demux,
5386 GstBuffer * buffer, gsize alignment)
5390 gst_buffer_map (buffer, &map, GST_MAP_READ);
5392 if (map.size < sizeof (guintptr)) {
5393 gst_buffer_unmap (buffer, &map);
5397 if (((guintptr) map.data) & (alignment - 1)) {
5398 GstBuffer *new_buffer;
5399 GstAllocationParams params = { 0, alignment - 1, 0, 0, };
5401 new_buffer = gst_buffer_new_allocate (NULL,
5402 gst_buffer_get_size (buffer), ¶ms);
5404 /* Copy data "by hand", so ensure alignment is kept: */
5405 gst_buffer_fill (new_buffer, 0, map.data, map.size);
5407 gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
5408 GST_DEBUG_OBJECT (demux,
5409 "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
5412 gst_buffer_unmap (buffer, &map);
5413 gst_buffer_unref (buffer);
5418 gst_buffer_unmap (buffer, &map);
5423 convert_to_ccdata (const guint8 * ccpair, guint8 ccpair_size, guint field,
5429 /* We are converting from pairs to triplets */
5430 *res = ccpair_size / 2 * 3;
5431 storage = g_malloc (*res);
5432 for (i = 0; i * 2 < ccpair_size; i += 1) {
5434 storage[i * 3] = 0xfc;
5436 storage[i * 3] = 0xfd;
5437 storage[i * 3 + 1] = ccpair[i * 2];
5438 storage[i * 3 + 2] = ccpair[i * 2 + 1];
5445 extract_cc_from_data (QtDemuxStream * stream, const guint8 * data, gsize size,
5449 guint32 atom_length, fourcc;
5450 QtDemuxStreamStsdEntry *stsd_entry;
5452 GST_MEMDUMP ("caption atom", data, size);
5454 /* There might be multiple atoms */
5459 atom_length = QT_UINT32 (data);
5460 fourcc = QT_FOURCC (data + 4);
5461 if (G_UNLIKELY (atom_length > size || atom_length == 8))
5464 GST_DEBUG_OBJECT (stream->pad, "here");
5466 /* Check if we have somethig compatible */
5467 stsd_entry = CUR_STREAM (stream);
5468 switch (stsd_entry->fourcc) {
5470 guint8 *cdat = NULL, *cdt2 = NULL;
5471 gsize cdat_size = 0, cdt2_size = 0;
5472 /* Should be cdat or cdt2 */
5473 if (fourcc != FOURCC_cdat && fourcc != FOURCC_cdt2) {
5474 GST_WARNING_OBJECT (stream->pad,
5475 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA608",
5476 GST_FOURCC_ARGS (fourcc));
5480 /* Convert to cc_data triplet */
5481 if (fourcc == FOURCC_cdat)
5482 cdat = convert_to_ccdata (data + 8, atom_length - 8, 1, &cdat_size);
5484 cdt2 = convert_to_ccdata (data + 8, atom_length - 8, 2, &cdt2_size);
5485 GST_DEBUG_OBJECT (stream->pad, "size:%" G_GSIZE_FORMAT " atom_length:%u",
5488 /* Check for another atom ? */
5489 if (size > atom_length + 8) {
5490 guint32 new_atom_length = QT_UINT32 (data + atom_length);
5491 if (size >= atom_length + new_atom_length) {
5492 fourcc = QT_FOURCC (data + atom_length + 4);
5493 if (fourcc == FOURCC_cdat) {
5496 convert_to_ccdata (data + atom_length + 8,
5497 new_atom_length - 8, 1, &cdat_size);
5499 GST_WARNING_OBJECT (stream->pad,
5500 "Got multiple [cdat] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5504 convert_to_ccdata (data + atom_length + 8,
5505 new_atom_length - 8, 2, &cdt2_size);
5507 GST_WARNING_OBJECT (stream->pad,
5508 "Got multiple [cdt2] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5513 *cclen = cdat_size + cdt2_size;
5514 res = g_malloc (*cclen);
5516 memcpy (res, cdat, cdat_size);
5518 memcpy (res + cdat_size, cdt2, cdt2_size);
5524 if (fourcc != FOURCC_ccdp) {
5525 GST_WARNING_OBJECT (stream->pad,
5526 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA708",
5527 GST_FOURCC_ARGS (fourcc));
5530 *cclen = atom_length - 8;
5531 res = g_memdup (data + 8, *cclen);
5534 /* Keep this here in case other closed caption formats are added */
5535 g_assert_not_reached ();
5539 GST_MEMDUMP ("Output", res, *cclen);
5544 GST_WARNING ("[cdat] atom is too small or invalid");
5548 /* the input buffer metadata must be writable,
5549 * but time/duration etc not yet set and need not be preserved */
5551 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5558 /* not many cases for now */
5559 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_mp4s)) {
5560 /* send a one time dvd clut event */
5561 if (stream->pending_event && stream->pad)
5562 gst_pad_push_event (stream->pad, stream->pending_event);
5563 stream->pending_event = NULL;
5566 if (G_UNLIKELY (stream->subtype != FOURCC_text
5567 && stream->subtype != FOURCC_sbtl &&
5568 stream->subtype != FOURCC_subp && stream->subtype != FOURCC_clcp)) {
5572 gst_buffer_map (buf, &map, GST_MAP_READ);
5574 /* empty buffer is sent to terminate previous subtitle */
5575 if (map.size <= 2) {
5576 gst_buffer_unmap (buf, &map);
5577 gst_buffer_unref (buf);
5580 if (stream->subtype == FOURCC_subp) {
5581 /* That's all the processing needed for subpictures */
5582 gst_buffer_unmap (buf, &map);
5586 if (stream->subtype == FOURCC_clcp) {
5589 /* For closed caption, we need to extract the information from the
5590 * [cdat],[cdt2] or [ccdp] atom */
5591 cc = extract_cc_from_data (stream, map.data, map.size, &cclen);
5592 gst_buffer_unmap (buf, &map);
5593 gst_buffer_unref (buf);
5595 buf = _gst_buffer_new_wrapped (cc, cclen, g_free);
5597 /* Conversion failed or there's nothing */
5603 nsize = GST_READ_UINT16_BE (map.data);
5604 nsize = MIN (nsize, map.size - 2);
5606 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5609 /* takes care of UTF-8 validation or UTF-16 recognition,
5610 * no other encoding expected */
5611 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5612 gst_buffer_unmap (buf, &map);
5614 gst_buffer_unref (buf);
5615 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5617 /* this should not really happen unless the subtitle is corrupted */
5618 gst_buffer_unref (buf);
5622 /* FIXME ? convert optional subsequent style info to markup */
5627 /* Sets a buffer's attributes properly and pushes it downstream.
5628 * Also checks for additional actions and custom processing that may
5629 * need to be done first.
5631 static GstFlowReturn
5632 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
5633 QtDemuxStream * stream, GstBuffer * buf,
5634 GstClockTime dts, GstClockTime pts, GstClockTime duration,
5635 gboolean keyframe, GstClockTime position, guint64 byte_position)
5637 GstFlowReturn ret = GST_FLOW_OK;
5639 /* offset the timestamps according to the edit list */
5641 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) {
5645 gst_buffer_map (buf, &map, GST_MAP_READ);
5646 url = g_strndup ((gchar *) map.data, map.size);
5647 gst_buffer_unmap (buf, &map);
5648 if (url != NULL && strlen (url) != 0) {
5649 /* we have RTSP redirect now */
5650 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5651 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
5652 gst_structure_new ("redirect",
5653 "new-location", G_TYPE_STRING, url, NULL)));
5654 qtdemux->posted_redirect = TRUE;
5656 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
5662 /* position reporting */
5663 if (qtdemux->segment.rate >= 0) {
5664 qtdemux->segment.position = position;
5665 gst_qtdemux_sync_streams (qtdemux);
5668 if (G_UNLIKELY (!stream->pad)) {
5669 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
5670 gst_buffer_unref (buf);
5674 /* send out pending buffers */
5675 while (stream->buffers) {
5676 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
5678 if (G_UNLIKELY (stream->discont)) {
5679 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5680 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
5681 stream->discont = FALSE;
5683 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5686 if (stream->alignment > 1)
5687 buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
5688 gst_pad_push (stream->pad, buffer);
5690 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
5693 /* we're going to modify the metadata */
5694 buf = gst_buffer_make_writable (buf);
5696 if (G_UNLIKELY (stream->need_process))
5697 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
5703 GST_BUFFER_DTS (buf) = dts;
5704 GST_BUFFER_PTS (buf) = pts;
5705 GST_BUFFER_DURATION (buf) = duration;
5706 GST_BUFFER_OFFSET (buf) = -1;
5707 GST_BUFFER_OFFSET_END (buf) = -1;
5709 if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette))
5710 gst_buffer_append_memory (buf,
5711 gst_memory_ref (CUR_STREAM (stream)->rgb8_palette));
5713 if (G_UNLIKELY (CUR_STREAM (stream)->padding)) {
5714 gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1);
5717 if (G_UNLIKELY (qtdemux->element_index)) {
5718 GstClockTime stream_time;
5721 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
5723 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
5724 GST_LOG_OBJECT (qtdemux,
5725 "adding association %" GST_TIME_FORMAT "-> %"
5726 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
5727 gst_index_add_association (qtdemux->element_index,
5729 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
5730 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
5731 GST_FORMAT_BYTES, byte_position, NULL);
5736 if (stream->need_clip)
5737 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5739 if (G_UNLIKELY (buf == NULL))
5742 if (G_UNLIKELY (stream->discont)) {
5743 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5744 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5745 stream->discont = FALSE;
5747 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5751 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
5752 stream->on_keyframe = FALSE;
5754 stream->on_keyframe = TRUE;
5758 GST_LOG_OBJECT (qtdemux,
5759 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5760 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
5761 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
5762 GST_PAD_NAME (stream->pad));
5764 if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) {
5765 GstStructure *crypto_info;
5766 QtDemuxCencSampleSetInfo *info =
5767 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5771 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5772 gst_pad_push_event (stream->pad, event);
5775 if (info->crypto_info == NULL) {
5776 GST_DEBUG_OBJECT (qtdemux, "cenc metadata hasn't been parsed yet");
5777 gst_buffer_unref (buf);
5781 /* The end of the crypto_info array matches our n_samples position,
5782 * so count backward from there */
5783 index = stream->sample_index - stream->n_samples + info->crypto_info->len;
5784 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5785 /* steal structure from array */
5786 crypto_info = g_ptr_array_index (info->crypto_info, index);
5787 g_ptr_array_index (info->crypto_info, index) = NULL;
5788 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
5789 info->crypto_info->len);
5790 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5791 GST_ERROR_OBJECT (qtdemux, "failed to attach cenc metadata to buffer");
5793 GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
5794 index, stream->sample_index);
5798 if (stream->alignment > 1)
5799 buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
5801 ret = gst_pad_push (stream->pad, buf);
5803 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
5804 /* mark position in stream, we'll need this to know when to send GAP event */
5805 stream->segment.position = pts + duration;
5812 static const QtDemuxRandomAccessEntry *
5813 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5814 GstClockTime pos, gboolean after)
5816 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
5817 guint n_entries = stream->n_ra_entries;
5820 /* we assume the table is sorted */
5821 for (i = 0; i < n_entries; ++i) {
5822 if (entries[i].ts > pos)
5826 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
5827 * probably okay to assume that the index lists the very first fragment */
5834 return &entries[i - 1];
5838 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
5840 const QtDemuxRandomAccessEntry *best_entry = NULL;
5843 GST_OBJECT_LOCK (qtdemux);
5845 g_assert (qtdemux->n_streams > 0);
5847 /* first see if we can determine where to go to using mfra,
5848 * before we start clearing things */
5849 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
5850 const QtDemuxRandomAccessEntry *entry;
5851 QtDemuxStream *stream;
5852 gboolean is_audio_or_video;
5854 stream = QTDEMUX_STREAM (iter->data);
5856 if (stream->ra_entries == NULL)
5859 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
5860 is_audio_or_video = TRUE;
5862 is_audio_or_video = FALSE;
5865 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
5866 stream->time_position, !is_audio_or_video);
5868 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
5869 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
5871 stream->pending_seek = entry;
5873 /* decide position to jump to just based on audio/video tracks, not subs */
5874 if (!is_audio_or_video)
5877 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
5881 /* no luck, will handle seek otherwise */
5882 if (best_entry == NULL) {
5883 GST_OBJECT_UNLOCK (qtdemux);
5887 /* ok, now we can prepare for processing as of located moof */
5888 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
5889 QtDemuxStream *stream;
5891 stream = QTDEMUX_STREAM (iter->data);
5893 g_free (stream->samples);
5894 stream->samples = NULL;
5895 stream->n_samples = 0;
5896 stream->stbl_index = -1; /* no samples have yet been parsed */
5897 stream->sample_index = -1;
5899 if (stream->protection_scheme_info) {
5900 /* Clear out any old cenc crypto info entries as we'll move to a new moof */
5901 if (stream->protection_scheme_type == FOURCC_cenc) {
5902 QtDemuxCencSampleSetInfo *info =
5903 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5904 if (info->crypto_info) {
5905 g_ptr_array_free (info->crypto_info, TRUE);
5906 info->crypto_info = NULL;
5912 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
5913 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
5914 GST_TIME_ARGS (QTDEMUX_FIRST_STREAM (qtdemux)->time_position),
5915 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
5917 qtdemux->moof_offset = best_entry->moof_offset;
5919 qtdemux_add_fragmented_samples (qtdemux);
5921 GST_OBJECT_UNLOCK (qtdemux);
5925 static GstFlowReturn
5926 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
5928 GstFlowReturn ret = GST_FLOW_OK;
5929 GstBuffer *buf = NULL;
5930 QtDemuxStream *stream, *target_stream = NULL;
5931 GstClockTime min_time;
5933 GstClockTime dts = GST_CLOCK_TIME_NONE;
5934 GstClockTime pts = GST_CLOCK_TIME_NONE;
5935 GstClockTime duration = 0;
5936 gboolean keyframe = FALSE;
5937 guint sample_size = 0;
5942 gst_qtdemux_push_pending_newsegment (qtdemux);
5944 if (qtdemux->fragmented_seek_pending) {
5945 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
5946 if (gst_qtdemux_do_fragmented_seek (qtdemux)) {
5947 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
5948 qtdemux->fragmented_seek_pending = FALSE;
5950 GST_INFO_OBJECT (qtdemux, "fragmented seek still pending");
5954 /* Figure out the next stream sample to output, min_time is expressed in
5955 * global time and runs over the edit list segments. */
5956 min_time = G_MAXUINT64;
5957 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
5958 GstClockTime position;
5960 stream = QTDEMUX_STREAM (iter->data);
5961 position = stream->time_position;
5963 /* position of -1 is EOS */
5964 if (position != GST_CLOCK_TIME_NONE && position < min_time) {
5965 min_time = position;
5966 target_stream = stream;
5970 if (G_UNLIKELY (target_stream == NULL)) {
5971 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
5975 /* check for segment end */
5976 if (G_UNLIKELY (qtdemux->segment.stop != -1
5977 && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
5978 || (qtdemux->segment.rate < 0
5979 && qtdemux->segment.start > min_time))
5980 && target_stream->on_keyframe)) {
5981 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
5982 target_stream->time_position = GST_CLOCK_TIME_NONE;
5986 /* gap events for subtitle streams */
5987 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
5988 stream = QTDEMUX_STREAM (iter->data);
5989 if (stream->pad && (stream->subtype == FOURCC_subp
5990 || stream->subtype == FOURCC_text
5991 || stream->subtype == FOURCC_sbtl)) {
5992 /* send one second gap events until the stream catches up */
5993 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
5994 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
5995 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
5996 stream->segment.position + GST_SECOND < min_time) {
5998 gst_event_new_gap (stream->segment.position, GST_SECOND);
5999 gst_pad_push_event (stream->pad, gap);
6000 stream->segment.position += GST_SECOND;
6005 stream = target_stream;
6006 /* fetch info for the current sample of this stream */
6007 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
6008 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
6011 gst_qtdemux_stream_check_and_change_stsd_index (qtdemux, stream);
6012 if (stream->new_caps) {
6013 gst_qtdemux_configure_stream (qtdemux, stream);
6014 qtdemux_do_allocation (qtdemux, stream);
6017 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
6018 if (G_UNLIKELY (qtdemux->
6019 segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
6020 if (stream->subtype == FOURCC_vide && !keyframe) {
6021 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on track-id %u",
6027 GST_DEBUG_OBJECT (qtdemux,
6028 "pushing from track-id %u, empty %d offset %" G_GUINT64_FORMAT
6029 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
6030 ", duration %" GST_TIME_FORMAT, stream->track_id, empty, offset,
6031 sample_size, GST_TIME_ARGS (dts), GST_TIME_ARGS (pts),
6032 GST_TIME_ARGS (duration));
6034 if (G_UNLIKELY (empty)) {
6035 /* empty segment, push a gap if there's a second or more
6036 * difference and move to the next one */
6037 if ((pts + duration - stream->segment.position) >= GST_SECOND)
6038 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
6039 stream->segment.position = pts + duration;
6043 /* hmm, empty sample, skip and move to next sample */
6044 if (G_UNLIKELY (sample_size <= 0))
6047 /* last pushed sample was out of boundary, goto next sample */
6048 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
6051 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
6054 GST_DEBUG_OBJECT (qtdemux,
6055 "size %d larger than stream max_buffer_size %d, trimming",
6056 sample_size, stream->max_buffer_size);
6058 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
6061 if (qtdemux->cenc_aux_info_offset > 0) {
6064 GstBuffer *aux_info = NULL;
6066 /* pull the data stored before the sample */
6068 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
6069 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
6070 if (G_UNLIKELY (ret != GST_FLOW_OK))
6072 gst_buffer_map (aux_info, &map, GST_MAP_READ);
6073 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
6074 gst_byte_reader_init (&br, map.data + 8, map.size);
6075 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
6076 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
6077 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
6078 gst_buffer_unmap (aux_info, &map);
6079 gst_buffer_unref (aux_info);
6080 ret = GST_FLOW_ERROR;
6083 gst_buffer_unmap (aux_info, &map);
6084 gst_buffer_unref (aux_info);
6087 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
6090 if (stream->use_allocator) {
6091 /* if we have a per-stream allocator, use it */
6092 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
6095 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
6097 if (G_UNLIKELY (ret != GST_FLOW_OK))
6100 if (size != sample_size) {
6101 pts += gst_util_uint64_scale_int (GST_SECOND,
6102 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6105 gst_util_uint64_scale_int (GST_SECOND,
6106 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6109 gst_util_uint64_scale_int (GST_SECOND,
6110 size / CUR_STREAM (stream)->bytes_per_frame, stream->timescale);
6113 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
6114 dts, pts, duration, keyframe, min_time, offset);
6116 if (size != sample_size) {
6117 QtDemuxSample *sample = &stream->samples[stream->sample_index];
6118 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6120 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
6122 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame);
6123 if (time_position >= segment->media_start) {
6124 /* inside the segment, update time_position, looks very familiar to
6125 * GStreamer segments, doesn't it? */
6126 stream->time_position = (time_position - segment->media_start) +
6129 /* not yet in segment, time does not yet increment. This means
6130 * that we are still prerolling keyframes to the decoder so it can
6131 * decode the first sample of the segment. */
6132 stream->time_position = segment->time;
6137 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
6138 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
6139 * we have no more data for the pad to push */
6140 if (ret == GST_FLOW_EOS)
6143 stream->offset_in_sample += size;
6144 if (stream->offset_in_sample >= sample_size) {
6145 gst_qtdemux_advance_sample (qtdemux, stream);
6150 gst_qtdemux_advance_sample (qtdemux, stream);
6158 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
6164 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
6165 /* EOS will be raised if all are EOS */
6172 gst_qtdemux_loop (GstPad * pad)
6174 GstQTDemux *qtdemux;
6178 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
6180 cur_offset = qtdemux->offset;
6181 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
6182 cur_offset, qt_demux_state_string (qtdemux->state));
6184 switch (qtdemux->state) {
6185 case QTDEMUX_STATE_INITIAL:
6186 case QTDEMUX_STATE_HEADER:
6187 ret = gst_qtdemux_loop_state_header (qtdemux);
6189 case QTDEMUX_STATE_MOVIE:
6190 ret = gst_qtdemux_loop_state_movie (qtdemux);
6191 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
6192 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
6200 /* if something went wrong, pause */
6201 if (ret != GST_FLOW_OK)
6205 gst_object_unref (qtdemux);
6211 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
6212 (NULL), ("streaming stopped, invalid state"));
6213 gst_pad_pause_task (pad);
6214 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6219 const gchar *reason = gst_flow_get_name (ret);
6221 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
6223 gst_pad_pause_task (pad);
6225 /* fatal errors need special actions */
6227 if (ret == GST_FLOW_EOS) {
6228 if (qtdemux->n_streams == 0) {
6229 /* we have no streams, post an error */
6230 gst_qtdemux_post_no_playable_stream_error (qtdemux);
6232 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
6235 if ((stop = qtdemux->segment.stop) == -1)
6236 stop = qtdemux->segment.duration;
6238 if (qtdemux->segment.rate >= 0) {
6239 GstMessage *message;
6242 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
6243 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6244 GST_FORMAT_TIME, stop);
6245 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
6246 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6247 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6248 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6250 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6251 gst_qtdemux_push_event (qtdemux, event);
6253 GstMessage *message;
6256 /* For Reverse Playback */
6257 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
6258 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6259 GST_FORMAT_TIME, qtdemux->segment.start);
6260 event = gst_event_new_segment_done (GST_FORMAT_TIME,
6261 qtdemux->segment.start);
6262 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6263 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6264 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6266 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6267 gst_qtdemux_push_event (qtdemux, event);
6272 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
6273 event = gst_event_new_eos ();
6274 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
6275 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6276 gst_qtdemux_push_event (qtdemux, event);
6278 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
6279 GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
6280 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6289 * Returns if there are samples to be played.
6292 has_next_entry (GstQTDemux * demux)
6294 QtDemuxStream *stream;
6297 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
6299 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
6300 stream = QTDEMUX_STREAM (iter->data);
6302 if (stream->sample_index == -1) {
6303 stream->sample_index = 0;
6304 stream->offset_in_sample = 0;
6307 if (stream->sample_index >= stream->n_samples) {
6308 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6311 GST_DEBUG_OBJECT (demux, "Found a sample");
6315 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
6322 * Returns the size of the first entry at the current offset.
6323 * If -1, there are none (which means EOS or empty file).
6326 next_entry_size (GstQTDemux * demux)
6328 QtDemuxStream *stream, *target_stream = NULL;
6329 guint64 smalloffs = (guint64) - 1;
6330 QtDemuxSample *sample;
6333 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
6336 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
6337 stream = QTDEMUX_STREAM (iter->data);
6339 if (stream->sample_index == -1) {
6340 stream->sample_index = 0;
6341 stream->offset_in_sample = 0;
6344 if (stream->sample_index >= stream->n_samples) {
6345 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6349 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
6350 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
6351 stream->sample_index);
6355 sample = &stream->samples[stream->sample_index];
6357 GST_LOG_OBJECT (demux,
6358 "Checking track-id %u (sample_index:%d / offset:%" G_GUINT64_FORMAT
6359 " / size:%" G_GUINT32_FORMAT ")", stream->track_id,
6360 stream->sample_index, sample->offset, sample->size);
6362 if (((smalloffs == -1)
6363 || (sample->offset < smalloffs)) && (sample->size)) {
6364 smalloffs = sample->offset;
6365 target_stream = stream;
6372 GST_LOG_OBJECT (demux,
6373 "track-id %u offset %" G_GUINT64_FORMAT " demux->offset :%"
6374 G_GUINT64_FORMAT, target_stream->track_id, smalloffs, demux->offset);
6376 stream = target_stream;
6377 sample = &stream->samples[stream->sample_index];
6379 if (sample->offset >= demux->offset) {
6380 demux->todrop = sample->offset - demux->offset;
6381 return sample->size + demux->todrop;
6384 GST_DEBUG_OBJECT (demux,
6385 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
6390 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
6392 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
6394 gst_element_post_message (GST_ELEMENT_CAST (demux),
6395 gst_message_new_element (GST_OBJECT_CAST (demux),
6396 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
6400 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
6405 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
6408 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
6409 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
6410 GST_SEEK_TYPE_NONE, -1);
6412 /* store seqnum to drop flush events, they don't need to reach downstream */
6413 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
6414 res = gst_pad_push_event (demux->sinkpad, event);
6415 demux->offset_seek_seqnum = GST_SEQNUM_INVALID;
6420 /* check for seekable upstream, above and beyond a mere query */
6422 gst_qtdemux_check_seekability (GstQTDemux * demux)
6425 gboolean seekable = FALSE;
6426 gint64 start = -1, stop = -1;
6428 if (demux->upstream_size)
6431 if (demux->upstream_format_is_time)
6434 query = gst_query_new_seeking (GST_FORMAT_BYTES);
6435 if (!gst_pad_peer_query (demux->sinkpad, query)) {
6436 GST_DEBUG_OBJECT (demux, "seeking query failed");
6440 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
6442 /* try harder to query upstream size if we didn't get it the first time */
6443 if (seekable && stop == -1) {
6444 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
6445 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
6448 /* if upstream doesn't know the size, it's likely that it's not seekable in
6449 * practice even if it technically may be seekable */
6450 if (seekable && (start != 0 || stop <= start)) {
6451 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
6456 gst_query_unref (query);
6458 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
6459 G_GUINT64_FORMAT ")", seekable, start, stop);
6460 demux->upstream_seekable = seekable;
6461 demux->upstream_size = seekable ? stop : -1;
6465 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
6467 g_return_if_fail (bytes <= demux->todrop);
6469 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
6470 gst_adapter_flush (demux->adapter, bytes);
6471 demux->neededbytes -= bytes;
6472 demux->offset += bytes;
6473 demux->todrop -= bytes;
6477 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
6479 if (G_UNLIKELY (demux->pending_newsegment)) {
6483 gst_qtdemux_push_pending_newsegment (demux);
6484 /* clear to send tags on all streams */
6485 for (iter = demux->active_streams, i = 0; iter;
6486 iter = g_list_next (iter), i++) {
6487 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
6488 gst_qtdemux_push_tags (demux, stream);
6489 if (CUR_STREAM (stream)->sparse) {
6490 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
6491 gst_pad_push_event (stream->pad,
6492 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
6499 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
6500 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
6502 GstClockTime ts, dur;
6507 stream->segments[segment_index].duration - (pos -
6508 stream->segments[segment_index].time);
6509 gap = gst_event_new_gap (ts, dur);
6510 stream->time_position += dur;
6512 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
6513 "segment: %" GST_PTR_FORMAT, gap);
6514 gst_pad_push_event (stream->pad, gap);
6518 gst_qtdemux_stream_send_initial_gap_segments (GstQTDemux * demux,
6519 QtDemuxStream * stream)
6523 /* Push any initial gap segments before proceeding to the
6525 for (i = 0; i < stream->n_segments; i++) {
6526 gst_qtdemux_activate_segment (demux, stream, i, stream->time_position);
6528 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
6529 gst_qtdemux_send_gap_for_segment (demux, stream, i,
6530 stream->time_position);
6532 /* Only support empty segment at the beginning followed by
6533 * one non-empty segment, this was checked when parsing the
6534 * edts atom, arriving here is unexpected */
6535 g_assert (i + 1 == stream->n_segments);
6541 static GstFlowReturn
6542 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
6546 demux = GST_QTDEMUX (parent);
6548 GST_DEBUG_OBJECT (demux,
6549 "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
6550 " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
6551 G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
6552 GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
6553 gst_buffer_get_size (inbuf), demux->offset);
6555 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
6556 gboolean is_gap_input = FALSE;
6559 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
6561 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
6562 QTDEMUX_STREAM (iter->data)->discont = TRUE;
6565 /* Check if we can land back on our feet in the case where upstream is
6566 * handling the seeking/pushing of samples with gaps in between (like
6567 * in the case of trick-mode DASH for example) */
6568 if (demux->upstream_format_is_time
6569 && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
6570 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
6572 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
6573 GST_LOG_OBJECT (demux,
6574 "track-id #%u , checking if offset %" G_GUINT64_FORMAT
6575 " is a sample start", stream->track_id, GST_BUFFER_OFFSET (inbuf));
6577 gst_qtdemux_find_index_for_given_media_offset_linear (demux,
6578 stream, GST_BUFFER_OFFSET (inbuf));
6580 QtDemuxSample *sample = &stream->samples[res];
6581 GST_LOG_OBJECT (demux,
6582 "Checking if sample %d from track-id %u is valid (offset:%"
6583 G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res,
6584 stream->track_id, sample->offset, sample->size);
6585 if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
6586 GST_LOG_OBJECT (demux,
6587 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
6589 is_gap_input = TRUE;
6590 /* We can go back to standard playback mode */
6591 demux->state = QTDEMUX_STATE_MOVIE;
6592 /* Remember which sample this stream is at */
6593 stream->sample_index = res;
6594 /* Finally update all push-based values to the expected values */
6595 demux->neededbytes = stream->samples[res].size;
6596 demux->offset = GST_BUFFER_OFFSET (inbuf);
6598 demux->mdatsize - demux->offset + demux->mdatoffset;
6603 if (!is_gap_input) {
6604 GST_DEBUG_OBJECT (demux, "Resetting, actual DISCONT");
6605 /* Reset state if it's a real discont */
6606 demux->neededbytes = 16;
6607 demux->state = QTDEMUX_STATE_INITIAL;
6608 demux->offset = GST_BUFFER_OFFSET (inbuf);
6609 gst_adapter_clear (demux->adapter);
6612 /* Reverse fragmented playback, need to flush all we have before
6613 * consuming a new fragment.
6614 * The samples array have the timestamps calculated by accumulating the
6615 * durations but this won't work for reverse playback of fragments as
6616 * the timestamps of a subsequent fragment should be smaller than the
6617 * previously received one. */
6618 if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
6619 gst_qtdemux_process_adapter (demux, TRUE);
6620 g_list_foreach (demux->active_streams,
6621 (GFunc) gst_qtdemux_stream_flush_samples_data, NULL);
6625 gst_adapter_push (demux->adapter, inbuf);
6627 GST_DEBUG_OBJECT (demux,
6628 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
6629 demux->neededbytes, gst_adapter_available (demux->adapter));
6631 return gst_qtdemux_process_adapter (demux, FALSE);
6634 static GstFlowReturn
6635 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
6637 GstFlowReturn ret = GST_FLOW_OK;
6639 /* we never really mean to buffer that much */
6640 if (demux->neededbytes == -1) {
6644 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
6645 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
6647 #ifndef GST_DISABLE_GST_DEBUG
6649 guint64 discont_offset, distance_from_discont;
6651 discont_offset = gst_adapter_offset_at_discont (demux->adapter);
6652 distance_from_discont =
6653 gst_adapter_distance_from_discont (demux->adapter);
6655 GST_DEBUG_OBJECT (demux,
6656 "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
6657 " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
6658 " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
6659 demux->offset, discont_offset, distance_from_discont);
6663 switch (demux->state) {
6664 case QTDEMUX_STATE_INITIAL:{
6669 gst_qtdemux_check_seekability (demux);
6671 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6673 /* get fourcc/length, set neededbytes */
6674 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
6676 gst_adapter_unmap (demux->adapter);
6678 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
6679 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
6681 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6682 (_("This file is invalid and cannot be played.")),
6683 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
6684 GST_FOURCC_ARGS (fourcc)));
6685 ret = GST_FLOW_ERROR;
6688 if (fourcc == FOURCC_mdat) {
6689 gint next_entry = next_entry_size (demux);
6690 if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
6691 /* we have the headers, start playback */
6692 demux->state = QTDEMUX_STATE_MOVIE;
6693 demux->neededbytes = next_entry;
6694 demux->mdatleft = size;
6695 demux->mdatsize = demux->mdatleft;
6697 /* no headers yet, try to get them */
6700 guint64 old, target;
6703 old = demux->offset;
6704 target = old + size;
6706 /* try to jump over the atom with a seek */
6707 /* only bother if it seems worth doing so,
6708 * and avoids possible upstream/server problems */
6709 if (demux->upstream_seekable &&
6710 demux->upstream_size > 4 * (1 << 20)) {
6711 res = qtdemux_seek_offset (demux, target);
6713 GST_DEBUG_OBJECT (demux, "skipping seek");
6718 GST_DEBUG_OBJECT (demux, "seek success");
6719 /* remember the offset fo the first mdat so we can seek back to it
6720 * after we have the headers */
6721 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
6722 demux->first_mdat = old;
6723 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
6726 /* seek worked, continue reading */
6727 demux->offset = target;
6728 demux->neededbytes = 16;
6729 demux->state = QTDEMUX_STATE_INITIAL;
6731 /* seek failed, need to buffer */
6732 demux->offset = old;
6733 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
6734 /* there may be multiple mdat (or alike) buffers */
6736 if (demux->mdatbuffer)
6737 bs = gst_buffer_get_size (demux->mdatbuffer);
6740 if (size + bs > 10 * (1 << 20))
6742 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
6743 demux->neededbytes = size;
6744 if (!demux->mdatbuffer)
6745 demux->mdatoffset = demux->offset;
6748 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
6749 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6750 (_("This file is invalid and cannot be played.")),
6751 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
6752 GST_FOURCC_ARGS (fourcc), size));
6753 ret = GST_FLOW_ERROR;
6756 /* this means we already started buffering and still no moov header,
6757 * let's continue buffering everything till we get moov */
6758 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
6759 || fourcc == FOURCC_moof))
6761 demux->neededbytes = size;
6762 demux->state = QTDEMUX_STATE_HEADER;
6766 case QTDEMUX_STATE_HEADER:{
6770 GST_DEBUG_OBJECT (demux, "In header");
6772 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6774 /* parse the header */
6775 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
6777 if (fourcc == FOURCC_moov) {
6780 /* in usual fragmented setup we could try to scan for more
6781 * and end up at the the moov (after mdat) again */
6782 if (demux->got_moov && demux->n_streams > 0 &&
6784 || demux->last_moov_offset == demux->offset)) {
6785 GST_DEBUG_OBJECT (demux,
6786 "Skipping moov atom as we have (this) one already");
6788 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
6790 if (demux->got_moov && demux->fragmented) {
6791 GST_DEBUG_OBJECT (demux,
6792 "Got a second moov, clean up data from old one");
6793 if (demux->moov_node_compressed) {
6794 g_node_destroy (demux->moov_node_compressed);
6795 if (demux->moov_node)
6796 g_free (demux->moov_node->data);
6798 demux->moov_node_compressed = NULL;
6799 if (demux->moov_node)
6800 g_node_destroy (demux->moov_node);
6801 demux->moov_node = NULL;
6803 /* prepare newsegment to send when streaming actually starts */
6804 if (!demux->pending_newsegment) {
6805 demux->pending_newsegment =
6806 gst_event_new_segment (&demux->segment);
6807 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
6808 gst_event_set_seqnum (demux->pending_newsegment,
6809 demux->segment_seqnum);
6813 demux->last_moov_offset = demux->offset;
6815 qtdemux_parse_moov (demux, data, demux->neededbytes);
6816 qtdemux_node_dump (demux, demux->moov_node);
6817 qtdemux_parse_tree (demux);
6818 qtdemux_prepare_streams (demux);
6819 if (!demux->got_moov)
6820 qtdemux_expose_streams (demux);
6823 for (iter = demux->active_streams; iter;
6824 iter = g_list_next (iter)) {
6825 gst_qtdemux_configure_stream (demux,
6826 QTDEMUX_STREAM (iter->data));
6830 demux->got_moov = TRUE;
6831 gst_qtdemux_check_send_pending_segment (demux);
6833 /* fragmented streams headers shouldn't contain edts atoms */
6834 if (!demux->fragmented) {
6835 for (iter = demux->active_streams; iter;
6836 iter = g_list_next (iter)) {
6837 gst_qtdemux_stream_send_initial_gap_segments (demux,
6838 QTDEMUX_STREAM (iter->data));
6842 if (demux->moov_node_compressed) {
6843 g_node_destroy (demux->moov_node_compressed);
6844 g_free (demux->moov_node->data);
6846 demux->moov_node_compressed = NULL;
6847 g_node_destroy (demux->moov_node);
6848 demux->moov_node = NULL;
6849 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
6851 } else if (fourcc == FOURCC_moof) {
6852 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
6854 GstClockTime prev_pts;
6855 guint64 prev_offset;
6856 guint64 adapter_discont_offset, adapter_discont_dist;
6858 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
6861 * The timestamp of the moof buffer is relevant as some scenarios
6862 * won't have the initial timestamp in the atoms. Whenever a new
6863 * buffer has started, we get that buffer's PTS and use it as a base
6864 * timestamp for the trun entries.
6866 * To keep track of the current buffer timestamp and starting point
6867 * we use gst_adapter_prev_pts that gives us the PTS and the distance
6868 * from the beggining of the buffer, with the distance and demux->offset
6869 * we know if it is still the same buffer or not.
6871 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
6872 prev_offset = demux->offset - dist;
6873 if (demux->fragment_start_offset == -1
6874 || prev_offset > demux->fragment_start_offset) {
6875 demux->fragment_start_offset = prev_offset;
6876 demux->fragment_start = prev_pts;
6877 GST_DEBUG_OBJECT (demux,
6878 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
6879 GST_TIME_FORMAT, demux->fragment_start_offset,
6880 GST_TIME_ARGS (demux->fragment_start));
6883 /* We can't use prev_offset() here because this would require
6884 * upstream to set consistent and correct offsets on all buffers
6885 * since the discont. Nothing ever did that in the past and we
6886 * would break backwards compatibility here then.
6887 * Instead take the offset we had at the last discont and count
6888 * the bytes from there. This works with old code as there would
6889 * be no discont between moov and moof, and also works with
6890 * adaptivedemux which correctly sets offset and will set the
6891 * DISCONT flag accordingly when needed.
6893 * We also only do this for upstream TIME segments as otherwise
6894 * there are potential backwards compatibility problems with
6895 * seeking in PUSH mode and upstream providing inconsistent
6897 adapter_discont_offset =
6898 gst_adapter_offset_at_discont (demux->adapter);
6899 adapter_discont_dist =
6900 gst_adapter_distance_from_discont (demux->adapter);
6902 GST_DEBUG_OBJECT (demux,
6903 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
6904 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
6905 demux->offset, adapter_discont_offset, adapter_discont_dist);
6907 if (demux->upstream_format_is_time) {
6908 demux->moof_offset = adapter_discont_offset;
6909 if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
6910 demux->moof_offset += adapter_discont_dist;
6911 if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
6912 demux->moof_offset = demux->offset;
6914 demux->moof_offset = demux->offset;
6917 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
6918 demux->moof_offset, NULL)) {
6919 gst_adapter_unmap (demux->adapter);
6920 ret = GST_FLOW_ERROR;
6923 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
6924 if (demux->mss_mode && !demux->exposed) {
6925 if (!demux->pending_newsegment) {
6926 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
6927 demux->pending_newsegment =
6928 gst_event_new_segment (&demux->segment);
6929 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
6930 gst_event_set_seqnum (demux->pending_newsegment,
6931 demux->segment_seqnum);
6933 qtdemux_expose_streams (demux);
6936 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
6938 } else if (fourcc == FOURCC_ftyp) {
6939 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
6940 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
6941 } else if (fourcc == FOURCC_uuid) {
6942 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
6943 qtdemux_parse_uuid (demux, data, demux->neededbytes);
6944 } else if (fourcc == FOURCC_sidx) {
6945 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
6946 qtdemux_parse_sidx (demux, data, demux->neededbytes);
6950 /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
6954 /* [free] and [skip] are padding atoms */
6955 GST_DEBUG_OBJECT (demux,
6956 "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
6957 GST_FOURCC_ARGS (fourcc));
6960 GST_WARNING_OBJECT (demux,
6961 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
6962 GST_FOURCC_ARGS (fourcc));
6963 /* Let's jump that one and go back to initial state */
6967 gst_adapter_unmap (demux->adapter);
6970 if (demux->mdatbuffer && demux->n_streams) {
6971 gsize remaining_data_size = 0;
6973 /* the mdat was before the header */
6974 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
6975 demux->n_streams, demux->mdatbuffer);
6976 /* restore our adapter/offset view of things with upstream;
6977 * put preceding buffered data ahead of current moov data.
6978 * This should also handle evil mdat, moov, mdat cases and alike */
6979 gst_adapter_flush (demux->adapter, demux->neededbytes);
6981 /* Store any remaining data after the mdat for later usage */
6982 remaining_data_size = gst_adapter_available (demux->adapter);
6983 if (remaining_data_size > 0) {
6984 g_assert (demux->restoredata_buffer == NULL);
6985 demux->restoredata_buffer =
6986 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
6987 demux->restoredata_offset = demux->offset + demux->neededbytes;
6988 GST_DEBUG_OBJECT (demux,
6989 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
6990 G_GUINT64_FORMAT, remaining_data_size,
6991 demux->restoredata_offset);
6994 gst_adapter_push (demux->adapter, demux->mdatbuffer);
6995 demux->mdatbuffer = NULL;
6996 demux->offset = demux->mdatoffset;
6997 demux->neededbytes = next_entry_size (demux);
6998 demux->state = QTDEMUX_STATE_MOVIE;
6999 demux->mdatleft = gst_adapter_available (demux->adapter);
7000 demux->mdatsize = demux->mdatleft;
7002 GST_DEBUG_OBJECT (demux, "Carrying on normally");
7003 gst_adapter_flush (demux->adapter, demux->neededbytes);
7005 /* only go back to the mdat if there are samples to play */
7006 if (demux->got_moov && demux->first_mdat != -1
7007 && has_next_entry (demux)) {
7010 /* we need to seek back */
7011 res = qtdemux_seek_offset (demux, demux->first_mdat);
7013 demux->offset = demux->first_mdat;
7015 GST_DEBUG_OBJECT (demux, "Seek back failed");
7018 demux->offset += demux->neededbytes;
7020 demux->neededbytes = 16;
7021 demux->state = QTDEMUX_STATE_INITIAL;
7026 case QTDEMUX_STATE_BUFFER_MDAT:{
7030 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
7032 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7033 gst_buffer_extract (buf, 0, fourcc, 4);
7034 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
7035 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
7036 if (demux->mdatbuffer)
7037 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
7039 demux->mdatbuffer = buf;
7040 demux->offset += demux->neededbytes;
7041 demux->neededbytes = 16;
7042 demux->state = QTDEMUX_STATE_INITIAL;
7043 gst_qtdemux_post_progress (demux, 1, 1);
7047 case QTDEMUX_STATE_MOVIE:{
7048 QtDemuxStream *stream = NULL;
7049 QtDemuxSample *sample;
7050 GstClockTime dts, pts, duration;
7054 GST_DEBUG_OBJECT (demux,
7055 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
7057 if (demux->fragmented) {
7058 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
7060 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
7061 /* if needed data starts within this atom,
7062 * then it should not exceed this atom */
7063 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
7064 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7065 (_("This file is invalid and cannot be played.")),
7066 ("sample data crosses atom boundary"));
7067 ret = GST_FLOW_ERROR;
7070 demux->mdatleft -= demux->neededbytes;
7072 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
7073 /* so we are dropping more than left in this atom */
7074 gst_qtdemux_drop_data (demux, demux->mdatleft);
7075 demux->mdatleft = 0;
7077 /* need to resume atom parsing so we do not miss any other pieces */
7078 demux->state = QTDEMUX_STATE_INITIAL;
7079 demux->neededbytes = 16;
7081 /* check if there was any stored post mdat data from previous buffers */
7082 if (demux->restoredata_buffer) {
7083 g_assert (gst_adapter_available (demux->adapter) == 0);
7085 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
7086 demux->restoredata_buffer = NULL;
7087 demux->offset = demux->restoredata_offset;
7094 if (demux->todrop) {
7095 if (demux->cenc_aux_info_offset > 0) {
7099 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
7100 data = gst_adapter_map (demux->adapter, demux->todrop);
7101 gst_byte_reader_init (&br, data + 8, demux->todrop);
7102 if (!qtdemux_parse_cenc_aux_info (demux,
7103 QTDEMUX_FIRST_STREAM (demux), &br,
7104 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
7105 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
7106 ret = GST_FLOW_ERROR;
7107 gst_adapter_unmap (demux->adapter);
7108 g_free (demux->cenc_aux_info_sizes);
7109 demux->cenc_aux_info_sizes = NULL;
7112 demux->cenc_aux_info_offset = 0;
7113 g_free (demux->cenc_aux_info_sizes);
7114 demux->cenc_aux_info_sizes = NULL;
7115 gst_adapter_unmap (demux->adapter);
7117 gst_qtdemux_drop_data (demux, demux->todrop);
7121 /* initial newsegment sent here after having added pads,
7122 * possible others in sink_event */
7123 gst_qtdemux_check_send_pending_segment (demux);
7125 /* Figure out which stream this packet belongs to */
7126 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
7127 stream = QTDEMUX_STREAM (iter->data);
7128 if (stream->sample_index >= stream->n_samples) {
7129 /* reset to be checked below G_UNLIKELY (stream == NULL) */
7133 GST_LOG_OBJECT (demux,
7134 "Checking track-id %u (sample_index:%d / offset:%"
7135 G_GUINT64_FORMAT " / size:%d)", stream->track_id,
7136 stream->sample_index,
7137 stream->samples[stream->sample_index].offset,
7138 stream->samples[stream->sample_index].size);
7140 if (stream->samples[stream->sample_index].offset == demux->offset)
7144 if (G_UNLIKELY (stream == NULL))
7145 goto unknown_stream;
7147 gst_qtdemux_stream_check_and_change_stsd_index (demux, stream);
7149 if (stream->new_caps) {
7150 gst_qtdemux_configure_stream (demux, stream);
7153 /* Put data in a buffer, set timestamps, caps, ... */
7154 sample = &stream->samples[stream->sample_index];
7156 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
7157 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
7158 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
7160 dts = QTSAMPLE_DTS (stream, sample);
7161 pts = QTSAMPLE_PTS (stream, sample);
7162 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
7163 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
7165 /* check for segment end */
7166 if (G_UNLIKELY (demux->segment.stop != -1
7167 && demux->segment.stop <= pts && stream->on_keyframe)) {
7168 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
7169 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
7171 /* skip this data, stream is EOS */
7172 gst_adapter_flush (demux->adapter, demux->neededbytes);
7173 demux->offset += demux->neededbytes;
7175 /* check if all streams are eos */
7177 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
7178 if (!STREAM_IS_EOS (QTDEMUX_STREAM (iter->data))) {
7187 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7189 /* FIXME: should either be an assert or a plain check */
7190 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
7192 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
7193 dts, pts, duration, keyframe, dts, demux->offset);
7197 ret = gst_qtdemux_combine_flows (demux, stream, ret);
7199 /* skip this data, stream is EOS */
7200 gst_adapter_flush (demux->adapter, demux->neededbytes);
7203 stream->sample_index++;
7204 stream->offset_in_sample = 0;
7206 /* update current offset and figure out size of next buffer */
7207 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
7208 demux->offset, demux->neededbytes);
7209 demux->offset += demux->neededbytes;
7210 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
7214 if (ret == GST_FLOW_EOS) {
7215 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
7216 demux->neededbytes = -1;
7220 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
7221 if (demux->fragmented) {
7222 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
7223 /* there may be more to follow, only finish this atom */
7224 demux->todrop = demux->mdatleft;
7225 demux->neededbytes = demux->todrop;
7230 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
7231 goto non_ok_unlinked_flow;
7240 /* when buffering movie data, at least show user something is happening */
7241 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
7242 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
7243 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
7244 demux->neededbytes);
7251 non_ok_unlinked_flow:
7253 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
7254 gst_flow_get_name (ret));
7259 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
7260 ret = GST_FLOW_ERROR;
7265 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
7271 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7272 (NULL), ("qtdemuxer invalid state %d", demux->state));
7273 ret = GST_FLOW_ERROR;
7278 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7279 (NULL), ("no 'moov' atom within the first 10 MB"));
7280 ret = GST_FLOW_ERROR;
7286 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
7291 query = gst_query_new_scheduling ();
7293 if (!gst_pad_peer_query (sinkpad, query)) {
7294 gst_query_unref (query);
7298 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
7299 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
7300 gst_query_unref (query);
7305 GST_DEBUG_OBJECT (sinkpad, "activating pull");
7306 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
7310 GST_DEBUG_OBJECT (sinkpad, "activating push");
7311 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
7316 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
7317 GstPadMode mode, gboolean active)
7320 GstQTDemux *demux = GST_QTDEMUX (parent);
7323 case GST_PAD_MODE_PUSH:
7324 demux->pullbased = FALSE;
7327 case GST_PAD_MODE_PULL:
7329 demux->pullbased = TRUE;
7330 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
7333 res = gst_pad_stop_task (sinkpad);
7345 qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
7351 memset (&z, 0, sizeof (z));
7356 if ((ret = inflateInit (&z)) != Z_OK) {
7357 GST_ERROR ("inflateInit() returned %d", ret);
7361 z.next_in = z_buffer;
7362 z.avail_in = z_length;
7364 buffer = (guint8 *) g_malloc (*length);
7365 z.avail_out = *length;
7366 z.next_out = (Bytef *) buffer;
7368 ret = inflate (&z, Z_NO_FLUSH);
7369 if (ret == Z_STREAM_END) {
7371 } else if (ret != Z_OK) {
7372 GST_WARNING ("inflate() returned %d", ret);
7377 buffer = (guint8 *) g_realloc (buffer, *length);
7378 z.next_out = (Bytef *) (buffer + z.total_out);
7379 z.avail_out += 4096;
7380 } while (z.avail_in > 0);
7382 if (ret != Z_STREAM_END) {
7387 *length = z.total_out;
7394 #endif /* HAVE_ZLIB */
7397 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
7401 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
7403 /* counts as header data */
7404 qtdemux->header_size += length;
7406 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
7407 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
7409 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
7416 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
7417 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
7418 if (dcom == NULL || cmvd == NULL)
7419 goto invalid_compression;
7421 dcom_len = QT_UINT32 (dcom->data);
7423 goto invalid_compression;
7425 method = QT_FOURCC ((guint8 *) dcom->data + 8);
7429 guint uncompressed_length;
7430 guint compressed_length;
7434 cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
7436 goto invalid_compression;
7438 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
7439 compressed_length = cmvd_len - 12;
7440 GST_LOG ("length = %u", uncompressed_length);
7443 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
7444 compressed_length, &uncompressed_length);
7447 qtdemux->moov_node_compressed = qtdemux->moov_node;
7448 qtdemux->moov_node = g_node_new (buf);
7450 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
7451 uncompressed_length);
7455 #endif /* HAVE_ZLIB */
7457 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
7458 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
7465 invalid_compression:
7467 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
7473 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
7476 while (G_UNLIKELY (buf < end)) {
7480 if (G_UNLIKELY (buf + 4 > end)) {
7481 GST_LOG_OBJECT (qtdemux, "buffer overrun");
7484 len = QT_UINT32 (buf);
7485 if (G_UNLIKELY (len == 0)) {
7486 GST_LOG_OBJECT (qtdemux, "empty container");
7489 if (G_UNLIKELY (len < 8)) {
7490 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
7493 if (G_UNLIKELY (len > (end - buf))) {
7494 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
7495 (gint) (end - buf));
7499 child = g_node_new ((guint8 *) buf);
7500 g_node_append (node, child);
7501 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
7502 qtdemux_parse_node (qtdemux, child, buf, len);
7510 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
7513 int len = QT_UINT32 (xdxt->data);
7514 guint8 *buf = xdxt->data;
7515 guint8 *end = buf + len;
7518 /* skip size and type */
7526 size = QT_UINT32 (buf);
7527 type = QT_FOURCC (buf + 4);
7529 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
7531 if (buf + size > end || size <= 0)
7537 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
7538 GST_FOURCC_ARGS (type));
7542 buffer = gst_buffer_new_and_alloc (size);
7543 gst_buffer_fill (buffer, 0, buf, size);
7544 stream->buffers = g_slist_append (stream->buffers, buffer);
7545 GST_LOG_OBJECT (qtdemux, "parsing theora header");
7548 buffer = gst_buffer_new_and_alloc (size);
7549 gst_buffer_fill (buffer, 0, buf, size);
7550 stream->buffers = g_slist_append (stream->buffers, buffer);
7551 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
7554 buffer = gst_buffer_new_and_alloc (size);
7555 gst_buffer_fill (buffer, 0, buf, size);
7556 stream->buffers = g_slist_append (stream->buffers, buffer);
7557 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
7560 GST_WARNING_OBJECT (qtdemux,
7561 "unknown theora cookie %" GST_FOURCC_FORMAT,
7562 GST_FOURCC_ARGS (type));
7571 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
7575 guint32 node_length = 0;
7576 const QtNodeType *type;
7579 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
7581 if (G_UNLIKELY (length < 8))
7582 goto not_enough_data;
7584 node_length = QT_UINT32 (buffer);
7585 fourcc = QT_FOURCC (buffer + 4);
7587 /* ignore empty nodes */
7588 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
7591 type = qtdemux_type_get (fourcc);
7593 end = buffer + length;
7595 GST_LOG_OBJECT (qtdemux,
7596 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
7597 GST_FOURCC_ARGS (fourcc), node_length, type->name);
7599 if (node_length > length)
7600 goto broken_atom_size;
7602 if (type->flags & QT_FLAG_CONTAINER) {
7603 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
7608 if (node_length < 20) {
7609 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
7612 GST_DEBUG_OBJECT (qtdemux,
7613 "parsing stsd (sample table, sample description) atom");
7614 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
7615 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7626 /* also read alac (or whatever) in stead of mp4a in the following,
7627 * since a similar layout is used in other cases as well */
7628 if (fourcc == FOURCC_mp4a)
7630 else if (fourcc == FOURCC_fLaC)
7635 /* There are two things we might encounter here: a true mp4a atom, and
7636 an mp4a entry in an stsd atom. The latter is what we're interested
7637 in, and it looks like an atom, but isn't really one. The true mp4a
7638 atom is short, so we detect it based on length here. */
7639 if (length < min_size) {
7640 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7641 GST_FOURCC_ARGS (fourcc));
7645 /* 'version' here is the sound sample description version. Types 0 and
7646 1 are documented in the QTFF reference, but type 2 is not: it's
7647 described in Apple header files instead (struct SoundDescriptionV2
7649 version = QT_UINT16 (buffer + 16);
7651 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
7652 GST_FOURCC_ARGS (fourcc), version);
7654 /* parse any esds descriptors */
7666 GST_WARNING_OBJECT (qtdemux,
7667 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
7668 GST_FOURCC_ARGS (fourcc), version);
7673 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7699 /* codec_data is contained inside these atoms, which all have
7700 * the same format. */
7701 /* video sample description size is 86 bytes without extension.
7702 * node_length have to be bigger than 86 bytes because video sample
7703 * description can include extenstions such as esds, fiel, glbl, etc. */
7704 if (node_length < 86) {
7705 GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
7706 " sample description length too short (%u < 86)",
7707 GST_FOURCC_ARGS (fourcc), node_length);
7711 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
7712 GST_FOURCC_ARGS (fourcc));
7714 /* version (2 bytes) : this is set to 0, unless a compressor has changed
7716 * revision level (2 bytes) : must be set to 0. */
7717 version = QT_UINT32 (buffer + 16);
7718 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
7720 /* compressor name : PASCAL string and informative purposes
7721 * first byte : the number of bytes to be displayed.
7722 * it has to be less than 32 because it is reserved
7723 * space of 32 bytes total including itself. */
7724 str_len = QT_UINT8 (buffer + 50);
7726 GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
7727 (char *) buffer + 51);
7729 GST_WARNING_OBJECT (qtdemux,
7730 "compressorname length too big (%u > 31)", str_len);
7732 GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
7734 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
7739 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
7741 /* You are reading this correctly. QTFF specifies that the
7742 * metadata atom is a short atom, whereas ISO BMFF specifies
7743 * it's a full atom. But since so many people are doing things
7744 * differently, we actually peek into the atom to see which
7747 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7748 GST_FOURCC_ARGS (fourcc));
7751 if (QT_FOURCC (buffer + 12) == FOURCC_hdlr) {
7752 /* Variant 1: What QTFF specifies. 'meta' is a short header which
7753 * starts with a 'hdlr' atom */
7754 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
7755 } else if (QT_UINT32 (buffer + 8) == 0x00000000) {
7756 /* Variant 2: What ISO BMFF specifies. 'meta' is a _full_ atom
7757 * with version/flags both set to zero */
7758 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
7760 GST_WARNING_OBJECT (qtdemux, "Unknown 'meta' atom format");
7765 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
7766 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
7767 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7776 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7777 GST_FOURCC_ARGS (fourcc));
7781 version = QT_UINT32 (buffer + 12);
7782 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
7789 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
7794 if (length < offset) {
7795 GST_WARNING_OBJECT (qtdemux,
7796 "skipping too small %" GST_FOURCC_FORMAT " box",
7797 GST_FOURCC_ARGS (fourcc));
7800 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7806 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
7811 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
7816 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
7820 if (!strcmp (type->name, "unknown"))
7821 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
7825 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
7826 GST_FOURCC_ARGS (fourcc));
7832 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7833 (_("This file is corrupt and cannot be played.")),
7834 ("Not enough data for an atom header, got only %u bytes", length));
7839 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7840 (_("This file is corrupt and cannot be played.")),
7841 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
7842 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
7849 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
7853 guint32 child_fourcc;
7855 for (child = g_node_first_child (node); child;
7856 child = g_node_next_sibling (child)) {
7857 buffer = (guint8 *) child->data;
7859 child_fourcc = QT_FOURCC (buffer + 4);
7861 if (G_UNLIKELY (child_fourcc == fourcc)) {
7869 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
7870 GstByteReader * parser)
7874 guint32 child_fourcc, child_len;
7876 for (child = g_node_first_child (node); child;
7877 child = g_node_next_sibling (child)) {
7878 buffer = (guint8 *) child->data;
7880 child_len = QT_UINT32 (buffer);
7881 child_fourcc = QT_FOURCC (buffer + 4);
7883 if (G_UNLIKELY (child_fourcc == fourcc)) {
7884 if (G_UNLIKELY (child_len < (4 + 4)))
7886 /* FIXME: must verify if atom length < parent atom length */
7887 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7895 qtdemux_tree_get_child_by_index (GNode * node, guint index)
7897 return g_node_nth_child (node, index);
7901 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
7902 GstByteReader * parser)
7906 guint32 child_fourcc, child_len;
7908 for (child = g_node_next_sibling (node); child;
7909 child = g_node_next_sibling (child)) {
7910 buffer = (guint8 *) child->data;
7912 child_fourcc = QT_FOURCC (buffer + 4);
7914 if (child_fourcc == fourcc) {
7916 child_len = QT_UINT32 (buffer);
7917 if (G_UNLIKELY (child_len < (4 + 4)))
7919 /* FIXME: must verify if atom length < parent atom length */
7920 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7929 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
7931 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
7935 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
7937 /* FIXME: This can only reliably work if demuxers have a
7938 * separate streaming thread per srcpad. This should be
7939 * done in a demuxer base class, which integrates parts
7942 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
7947 query = gst_query_new_allocation (stream->caps, FALSE);
7949 if (!gst_pad_peer_query (stream->pad, query)) {
7950 /* not a problem, just debug a little */
7951 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
7954 if (stream->allocator)
7955 gst_object_unref (stream->allocator);
7957 if (gst_query_get_n_allocation_params (query) > 0) {
7958 /* try the allocator */
7959 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
7961 stream->use_allocator = TRUE;
7963 stream->allocator = NULL;
7964 gst_allocation_params_init (&stream->params);
7965 stream->use_allocator = FALSE;
7967 gst_query_unref (query);
7972 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
7973 QtDemuxStream * stream)
7976 const gchar *selected_system;
7978 g_return_val_if_fail (qtdemux != NULL, FALSE);
7979 g_return_val_if_fail (stream != NULL, FALSE);
7980 g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1,
7983 if (stream->protection_scheme_type != FOURCC_cenc) {
7984 GST_ERROR_OBJECT (qtdemux, "unsupported protection scheme");
7987 if (qtdemux->protection_system_ids == NULL) {
7988 GST_ERROR_OBJECT (qtdemux, "stream is protected using cenc, but no "
7989 "cenc protection system information has been found");
7992 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
7993 selected_system = gst_protection_select_system ((const gchar **)
7994 qtdemux->protection_system_ids->pdata);
7995 g_ptr_array_remove_index (qtdemux->protection_system_ids,
7996 qtdemux->protection_system_ids->len - 1);
7997 if (!selected_system) {
7998 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
7999 "suitable decryptor element has been found");
8003 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8004 if (!gst_structure_has_name (s, "application/x-cenc")) {
8005 gst_structure_set (s,
8006 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
8007 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
8009 gst_structure_set_name (s, "application/x-cenc");
8015 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
8017 if (stream->subtype == FOURCC_vide) {
8018 /* fps is calculated base on the duration of the average framerate since
8019 * qt does not have a fixed framerate. */
8020 gboolean fps_available = TRUE;
8022 if ((stream->n_samples == 1 && stream->first_duration == 0)
8023 || (qtdemux->fragmented && stream->n_samples_moof == 1)) {
8025 CUR_STREAM (stream)->fps_n = 0;
8026 CUR_STREAM (stream)->fps_d = 1;
8028 if (stream->duration == 0 || stream->n_samples < 2) {
8029 CUR_STREAM (stream)->fps_n = stream->timescale;
8030 CUR_STREAM (stream)->fps_d = 1;
8031 fps_available = FALSE;
8033 GstClockTime avg_duration;
8037 /* duration and n_samples can be updated for fragmented format
8038 * so, framerate of fragmented format is calculated using data in a moof */
8039 if (qtdemux->fragmented && stream->n_samples_moof > 0
8040 && stream->duration_moof > 0) {
8041 n_samples = stream->n_samples_moof;
8042 duration = stream->duration_moof;
8044 n_samples = stream->n_samples;
8045 duration = stream->duration;
8048 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
8049 /* stream->duration is guint64, timescale, n_samples are guint32 */
8051 gst_util_uint64_scale_round (duration -
8052 stream->first_duration, GST_SECOND,
8053 (guint64) (stream->timescale) * (n_samples - 1));
8055 GST_LOG_OBJECT (qtdemux,
8056 "Calculating avg sample duration based on stream (or moof) duration %"
8058 " minus first sample %u, leaving %d samples gives %"
8059 GST_TIME_FORMAT, duration, stream->first_duration,
8060 n_samples - 1, GST_TIME_ARGS (avg_duration));
8062 gst_video_guess_framerate (avg_duration, &CUR_STREAM (stream)->fps_n,
8063 &CUR_STREAM (stream)->fps_d);
8065 GST_DEBUG_OBJECT (qtdemux,
8066 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
8067 stream->timescale, CUR_STREAM (stream)->fps_n,
8068 CUR_STREAM (stream)->fps_d);
8072 if (CUR_STREAM (stream)->caps) {
8073 CUR_STREAM (stream)->caps =
8074 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8076 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8077 "width", G_TYPE_INT, CUR_STREAM (stream)->width,
8078 "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL);
8080 /* set framerate if calculated framerate is reliable */
8081 if (fps_available) {
8082 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8083 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8084 CUR_STREAM (stream)->fps_d, NULL);
8087 /* calculate pixel-aspect-ratio using display width and height */
8088 GST_DEBUG_OBJECT (qtdemux,
8089 "video size %dx%d, target display size %dx%d",
8090 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height,
8091 stream->display_width, stream->display_height);
8092 /* qt file might have pasp atom */
8093 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8094 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w,
8095 CUR_STREAM (stream)->par_h);
8096 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8097 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8098 CUR_STREAM (stream)->par_h, NULL);
8099 } else if (stream->display_width > 0 && stream->display_height > 0
8100 && CUR_STREAM (stream)->width > 0
8101 && CUR_STREAM (stream)->height > 0) {
8104 /* calculate the pixel aspect ratio using the display and pixel w/h */
8105 n = stream->display_width * CUR_STREAM (stream)->height;
8106 d = stream->display_height * CUR_STREAM (stream)->width;
8109 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
8110 CUR_STREAM (stream)->par_w = n;
8111 CUR_STREAM (stream)->par_h = d;
8112 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8113 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8114 CUR_STREAM (stream)->par_h, NULL);
8117 if (CUR_STREAM (stream)->interlace_mode > 0) {
8118 if (CUR_STREAM (stream)->interlace_mode == 1) {
8119 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8120 G_TYPE_STRING, "progressive", NULL);
8121 } else if (CUR_STREAM (stream)->interlace_mode == 2) {
8122 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8123 G_TYPE_STRING, "interleaved", NULL);
8124 if (CUR_STREAM (stream)->field_order == 9) {
8125 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8126 G_TYPE_STRING, "top-field-first", NULL);
8127 } else if (CUR_STREAM (stream)->field_order == 14) {
8128 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8129 G_TYPE_STRING, "bottom-field-first", NULL);
8134 /* Create incomplete colorimetry here if needed */
8135 if (CUR_STREAM (stream)->colorimetry.range ||
8136 CUR_STREAM (stream)->colorimetry.matrix ||
8137 CUR_STREAM (stream)->colorimetry.transfer
8138 || CUR_STREAM (stream)->colorimetry.primaries) {
8139 gchar *colorimetry =
8140 gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry);
8141 gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry",
8142 G_TYPE_STRING, colorimetry, NULL);
8143 g_free (colorimetry);
8146 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
8147 guint par_w = 1, par_h = 1;
8149 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8150 par_w = CUR_STREAM (stream)->par_w;
8151 par_h = CUR_STREAM (stream)->par_h;
8154 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
8155 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w,
8157 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
8160 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8161 "multiview-mode", G_TYPE_STRING,
8162 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
8163 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
8164 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
8169 else if (stream->subtype == FOURCC_soun) {
8170 if (CUR_STREAM (stream)->caps) {
8171 CUR_STREAM (stream)->caps =
8172 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8173 if (CUR_STREAM (stream)->rate > 0)
8174 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8175 "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL);
8176 if (CUR_STREAM (stream)->n_channels > 0)
8177 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8178 "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL);
8179 if (CUR_STREAM (stream)->n_channels > 2) {
8180 /* FIXME: Need to parse the 'chan' atom to get channel layouts
8181 * correctly; this is just the minimum we can do - assume
8182 * we don't actually have any channel positions. */
8183 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8184 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
8190 GstCaps *prev_caps = NULL;
8192 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
8193 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
8194 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
8195 gst_pad_set_active (stream->pad, TRUE);
8197 gst_pad_use_fixed_caps (stream->pad);
8199 if (stream->protected) {
8200 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
8201 GST_ERROR_OBJECT (qtdemux,
8202 "Failed to configure protected stream caps.");
8207 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8208 CUR_STREAM (stream)->caps);
8209 if (stream->new_stream) {
8211 GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
8214 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
8217 gst_event_parse_stream_flags (event, &stream_flags);
8218 if (gst_event_parse_group_id (event, &qtdemux->group_id))
8219 qtdemux->have_group_id = TRUE;
8221 qtdemux->have_group_id = FALSE;
8222 gst_event_unref (event);
8223 } else if (!qtdemux->have_group_id) {
8224 qtdemux->have_group_id = TRUE;
8225 qtdemux->group_id = gst_util_group_id_next ();
8228 stream->new_stream = FALSE;
8229 event = gst_event_new_stream_start (stream->stream_id);
8230 if (qtdemux->have_group_id)
8231 gst_event_set_group_id (event, qtdemux->group_id);
8232 if (stream->disabled)
8233 stream_flags |= GST_STREAM_FLAG_UNSELECT;
8234 if (CUR_STREAM (stream)->sparse) {
8235 stream_flags |= GST_STREAM_FLAG_SPARSE;
8237 stream_flags &= ~GST_STREAM_FLAG_SPARSE;
8239 gst_event_set_stream_flags (event, stream_flags);
8240 gst_pad_push_event (stream->pad, event);
8243 prev_caps = gst_pad_get_current_caps (stream->pad);
8245 if (CUR_STREAM (stream)->caps) {
8247 || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) {
8248 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8249 CUR_STREAM (stream)->caps);
8250 gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps);
8252 GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
8255 GST_WARNING_OBJECT (qtdemux, "stream without caps");
8259 gst_caps_unref (prev_caps);
8260 stream->new_caps = FALSE;
8266 gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
8267 QtDemuxStream * stream)
8269 if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id)
8272 GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'",
8273 stream->cur_stsd_entry_index, stream->stsd_sample_description_id);
8274 if (G_UNLIKELY (stream->stsd_sample_description_id >=
8275 stream->stsd_entries_length)) {
8276 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
8277 (_("This file is invalid and cannot be played.")),
8278 ("New sample description id is out of bounds (%d >= %d)",
8279 stream->stsd_sample_description_id, stream->stsd_entries_length));
8281 stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
8282 stream->new_caps = TRUE;
8287 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
8288 QtDemuxStream * stream, GstTagList * list)
8290 gboolean ret = TRUE;
8291 /* consistent default for push based mode */
8292 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
8294 if (stream->subtype == FOURCC_vide) {
8295 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8298 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8301 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8302 gst_object_unref (stream->pad);
8308 qtdemux->n_video_streams++;
8309 } else if (stream->subtype == FOURCC_soun) {
8310 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
8313 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
8315 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8316 gst_object_unref (stream->pad);
8321 qtdemux->n_audio_streams++;
8322 } else if (stream->subtype == FOURCC_strm) {
8323 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
8324 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
8325 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
8326 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
8329 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
8331 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8332 gst_object_unref (stream->pad);
8337 qtdemux->n_sub_streams++;
8338 } else if (CUR_STREAM (stream)->caps) {
8339 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8342 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8344 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8345 gst_object_unref (stream->pad);
8350 qtdemux->n_video_streams++;
8352 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
8359 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
8360 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
8361 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
8362 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
8364 if (stream->stream_tags)
8365 gst_tag_list_unref (stream->stream_tags);
8366 stream->stream_tags = list;
8368 /* global tags go on each pad anyway */
8369 stream->send_global_tags = TRUE;
8370 /* send upstream GST_EVENT_PROTECTION events that were received before
8371 this source pad was created */
8372 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
8373 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
8377 gst_tag_list_unref (list);
8381 /* find next atom with @fourcc starting at @offset */
8382 static GstFlowReturn
8383 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
8384 guint64 * length, guint32 fourcc)
8390 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
8391 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
8397 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
8398 if (G_UNLIKELY (ret != GST_FLOW_OK))
8400 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
8403 gst_buffer_unref (buf);
8406 gst_buffer_map (buf, &map, GST_MAP_READ);
8407 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
8408 gst_buffer_unmap (buf, &map);
8409 gst_buffer_unref (buf);
8411 if (G_UNLIKELY (*length == 0)) {
8412 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
8413 ret = GST_FLOW_ERROR;
8417 if (lfourcc == fourcc) {
8418 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
8422 GST_LOG_OBJECT (qtdemux,
8423 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
8424 GST_FOURCC_ARGS (fourcc), *offset);
8433 /* might simply have had last one */
8434 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
8439 /* should only do something in pull mode */
8440 /* call with OBJECT lock */
8441 static GstFlowReturn
8442 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
8444 guint64 length, offset;
8445 GstBuffer *buf = NULL;
8446 GstFlowReturn ret = GST_FLOW_OK;
8447 GstFlowReturn res = GST_FLOW_OK;
8450 offset = qtdemux->moof_offset;
8451 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
8454 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8455 return GST_FLOW_EOS;
8458 /* best not do pull etc with lock held */
8459 GST_OBJECT_UNLOCK (qtdemux);
8461 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8462 if (ret != GST_FLOW_OK)
8465 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
8466 if (G_UNLIKELY (ret != GST_FLOW_OK))
8468 gst_buffer_map (buf, &map, GST_MAP_READ);
8469 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
8470 gst_buffer_unmap (buf, &map);
8471 gst_buffer_unref (buf);
8476 gst_buffer_unmap (buf, &map);
8477 gst_buffer_unref (buf);
8481 /* look for next moof */
8482 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8483 if (G_UNLIKELY (ret != GST_FLOW_OK))
8487 GST_OBJECT_LOCK (qtdemux);
8489 qtdemux->moof_offset = offset;
8495 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
8497 res = GST_FLOW_ERROR;
8502 /* maybe upstream temporarily flushing */
8503 if (ret != GST_FLOW_FLUSHING) {
8504 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8507 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
8508 /* resume at current position next time */
8515 /* initialise bytereaders for stbl sub-atoms */
8517 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
8519 stream->stbl_index = -1; /* no samples have yet been parsed */
8520 stream->sample_index = -1;
8522 /* time-to-sample atom */
8523 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
8526 /* copy atom data into a new buffer for later use */
8527 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
8529 /* skip version + flags */
8530 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
8531 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
8533 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
8535 /* make sure there's enough data */
8536 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
8537 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
8538 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
8539 stream->n_sample_times);
8540 if (!stream->n_sample_times)
8544 /* sync sample atom */
8545 stream->stps_present = FALSE;
8546 if ((stream->stss_present =
8547 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
8548 &stream->stss) ? TRUE : FALSE) == TRUE) {
8549 /* copy atom data into a new buffer for later use */
8550 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
8552 /* skip version + flags */
8553 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
8554 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
8557 if (stream->n_sample_syncs) {
8558 /* make sure there's enough data */
8559 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
8563 /* partial sync sample atom */
8564 if ((stream->stps_present =
8565 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
8566 &stream->stps) ? TRUE : FALSE) == TRUE) {
8567 /* copy atom data into a new buffer for later use */
8568 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
8570 /* skip version + flags */
8571 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
8572 !gst_byte_reader_get_uint32_be (&stream->stps,
8573 &stream->n_sample_partial_syncs))
8576 /* if there are no entries, the stss table contains the real
8578 if (stream->n_sample_partial_syncs) {
8579 /* make sure there's enough data */
8580 if (!qt_atom_parser_has_chunks (&stream->stps,
8581 stream->n_sample_partial_syncs, 4))
8588 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
8591 /* copy atom data into a new buffer for later use */
8592 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
8594 /* skip version + flags */
8595 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
8596 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
8599 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
8602 if (!stream->n_samples)
8605 /* sample-to-chunk atom */
8606 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
8609 /* copy atom data into a new buffer for later use */
8610 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
8612 /* skip version + flags */
8613 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
8614 !gst_byte_reader_get_uint32_be (&stream->stsc,
8615 &stream->n_samples_per_chunk))
8618 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
8619 stream->n_samples_per_chunk);
8621 /* make sure there's enough data */
8622 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
8628 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
8629 stream->co_size = sizeof (guint32);
8630 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
8632 stream->co_size = sizeof (guint64);
8636 /* copy atom data into a new buffer for later use */
8637 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
8639 /* skip version + flags */
8640 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
8643 /* chunks_are_samples == TRUE means treat chunks as samples */
8644 stream->chunks_are_samples = stream->sample_size
8645 && !CUR_STREAM (stream)->sampled;
8646 if (stream->chunks_are_samples) {
8647 /* treat chunks as samples */
8648 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
8651 /* skip number of entries */
8652 if (!gst_byte_reader_skip (&stream->stco, 4))
8655 /* make sure there are enough data in the stsz atom */
8656 if (!stream->sample_size) {
8657 /* different sizes for each sample */
8658 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
8663 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
8664 stream->n_samples, (guint) sizeof (QtDemuxSample),
8665 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
8667 if (stream->n_samples >=
8668 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
8669 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
8670 "be larger than %uMB (broken file?)", stream->n_samples,
8671 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
8675 g_assert (stream->samples == NULL);
8676 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
8677 if (!stream->samples) {
8678 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
8683 /* composition time-to-sample */
8684 if ((stream->ctts_present =
8685 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
8686 &stream->ctts) ? TRUE : FALSE) == TRUE) {
8687 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
8689 /* copy atom data into a new buffer for later use */
8690 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
8692 /* skip version + flags */
8693 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
8694 || !gst_byte_reader_get_uint32_be (&stream->ctts,
8695 &stream->n_composition_times))
8698 /* make sure there's enough data */
8699 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
8703 /* This is optional, if missing we iterate the ctts */
8704 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
8705 if (!gst_byte_reader_skip (&cslg, 1 + 3)
8706 || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
8707 g_free ((gpointer) cslg.data);
8711 gint32 cslg_least = 0;
8712 guint num_entries, pos;
8715 pos = gst_byte_reader_get_pos (&stream->ctts);
8716 num_entries = stream->n_composition_times;
8718 stream->cslg_shift = 0;
8720 for (i = 0; i < num_entries; i++) {
8723 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
8724 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8726 if (offset < cslg_least)
8727 cslg_least = offset;
8731 stream->cslg_shift = ABS (cslg_least);
8733 stream->cslg_shift = 0;
8735 /* reset the reader so we can generate sample table */
8736 gst_byte_reader_set_pos (&stream->ctts, pos);
8739 /* Ensure the cslg_shift value is consistent so we can use it
8740 * unconditionnally to produce TS and Segment */
8741 stream->cslg_shift = 0;
8748 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8749 (_("This file is corrupt and cannot be played.")), (NULL));
8754 gst_qtdemux_stbl_free (stream);
8755 if (!qtdemux->fragmented) {
8756 /* not quite good */
8757 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
8760 /* may pick up samples elsewhere */
8766 /* collect samples from the next sample to be parsed up to sample @n for @stream
8767 * by reading the info from @stbl
8769 * This code can be executed from both the streaming thread and the seeking
8770 * thread so it takes the object lock to protect itself
8773 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
8776 QtDemuxSample *samples, *first, *cur, *last;
8777 guint32 n_samples_per_chunk;
8780 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
8781 GST_FOURCC_FORMAT ", pad %s",
8782 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
8783 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
8785 n_samples = stream->n_samples;
8788 goto out_of_samples;
8790 GST_OBJECT_LOCK (qtdemux);
8791 if (n <= stream->stbl_index)
8792 goto already_parsed;
8794 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
8796 if (!stream->stsz.data) {
8797 /* so we already parsed and passed all the moov samples;
8798 * onto fragmented ones */
8799 g_assert (qtdemux->fragmented);
8803 /* pointer to the sample table */
8804 samples = stream->samples;
8806 /* starts from -1, moves to the next sample index to parse */
8807 stream->stbl_index++;
8809 /* keep track of the first and last sample to fill */
8810 first = &samples[stream->stbl_index];
8813 if (!stream->chunks_are_samples) {
8814 /* set the sample sizes */
8815 if (stream->sample_size == 0) {
8816 /* different sizes for each sample */
8817 for (cur = first; cur <= last; cur++) {
8818 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
8819 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
8820 (guint) (cur - samples), cur->size);
8823 /* samples have the same size */
8824 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
8825 for (cur = first; cur <= last; cur++)
8826 cur->size = stream->sample_size;
8830 n_samples_per_chunk = stream->n_samples_per_chunk;
8833 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
8836 if (stream->stsc_chunk_index >= stream->last_chunk
8837 || stream->stsc_chunk_index < stream->first_chunk) {
8838 stream->first_chunk =
8839 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8840 stream->samples_per_chunk =
8841 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8843 stream->stsd_sample_description_id =
8844 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
8846 /* chunk numbers are counted from 1 it seems */
8847 if (G_UNLIKELY (stream->first_chunk == 0))
8850 --stream->first_chunk;
8852 /* the last chunk of each entry is calculated by taking the first chunk
8853 * of the next entry; except if there is no next, where we fake it with
8855 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
8856 stream->last_chunk = G_MAXUINT32;
8858 stream->last_chunk =
8859 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
8860 if (G_UNLIKELY (stream->last_chunk == 0))
8863 --stream->last_chunk;
8866 GST_LOG_OBJECT (qtdemux,
8867 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
8868 "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
8869 stream->samples_per_chunk, stream->stsd_sample_description_id);
8871 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
8874 if (stream->last_chunk != G_MAXUINT32) {
8875 if (!qt_atom_parser_peek_sub (&stream->stco,
8876 stream->first_chunk * stream->co_size,
8877 (stream->last_chunk - stream->first_chunk) * stream->co_size,
8882 stream->co_chunk = stream->stco;
8883 if (!gst_byte_reader_skip (&stream->co_chunk,
8884 stream->first_chunk * stream->co_size))
8888 stream->stsc_chunk_index = stream->first_chunk;
8891 last_chunk = stream->last_chunk;
8893 if (stream->chunks_are_samples) {
8894 cur = &samples[stream->stsc_chunk_index];
8896 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8899 stream->stsc_chunk_index = j;
8904 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
8907 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
8908 "%" G_GUINT64_FORMAT, j, cur->offset);
8910 if (CUR_STREAM (stream)->samples_per_frame > 0 &&
8911 CUR_STREAM (stream)->bytes_per_frame > 0) {
8913 (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
8914 CUR_STREAM (stream)->samples_per_frame *
8915 CUR_STREAM (stream)->bytes_per_frame;
8917 cur->size = stream->samples_per_chunk;
8920 GST_DEBUG_OBJECT (qtdemux,
8921 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
8922 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
8923 stream->stco_sample_index)), cur->size);
8925 cur->timestamp = stream->stco_sample_index;
8926 cur->duration = stream->samples_per_chunk;
8927 cur->keyframe = TRUE;
8930 stream->stco_sample_index += stream->samples_per_chunk;
8932 stream->stsc_chunk_index = j;
8934 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8935 guint32 samples_per_chunk;
8936 guint64 chunk_offset;
8938 if (!stream->stsc_sample_index
8939 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
8940 &stream->chunk_offset))
8943 samples_per_chunk = stream->samples_per_chunk;
8944 chunk_offset = stream->chunk_offset;
8946 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
8947 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
8948 G_GUINT64_FORMAT " and size %d",
8949 (guint) (cur - samples), chunk_offset, cur->size);
8951 cur->offset = chunk_offset;
8952 chunk_offset += cur->size;
8955 if (G_UNLIKELY (cur > last)) {
8957 stream->stsc_sample_index = k + 1;
8958 stream->chunk_offset = chunk_offset;
8959 stream->stsc_chunk_index = j;
8963 stream->stsc_sample_index = 0;
8965 stream->stsc_chunk_index = j;
8967 stream->stsc_index++;
8970 if (stream->chunks_are_samples)
8974 guint32 n_sample_times;
8976 n_sample_times = stream->n_sample_times;
8979 for (i = stream->stts_index; i < n_sample_times; i++) {
8980 guint32 stts_samples;
8981 gint32 stts_duration;
8984 if (stream->stts_sample_index >= stream->stts_samples
8985 || !stream->stts_sample_index) {
8987 stream->stts_samples =
8988 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8989 stream->stts_duration =
8990 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8992 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
8993 i, stream->stts_samples, stream->stts_duration);
8995 stream->stts_sample_index = 0;
8998 stts_samples = stream->stts_samples;
8999 stts_duration = stream->stts_duration;
9000 stts_time = stream->stts_time;
9002 for (j = stream->stts_sample_index; j < stts_samples; j++) {
9003 GST_DEBUG_OBJECT (qtdemux,
9004 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
9005 (guint) (cur - samples), j,
9006 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
9008 cur->timestamp = stts_time;
9009 cur->duration = stts_duration;
9011 /* avoid 32-bit wrap-around,
9012 * but still mind possible 'negative' duration */
9013 stts_time += (gint64) stts_duration;
9016 if (G_UNLIKELY (cur > last)) {
9018 stream->stts_time = stts_time;
9019 stream->stts_sample_index = j + 1;
9020 if (stream->stts_sample_index >= stream->stts_samples)
9021 stream->stts_index++;
9025 stream->stts_sample_index = 0;
9026 stream->stts_time = stts_time;
9027 stream->stts_index++;
9029 /* fill up empty timestamps with the last timestamp, this can happen when
9030 * the last samples do not decode and so we don't have timestamps for them.
9031 * We however look at the last timestamp to estimate the track length so we
9032 * need something in here. */
9033 for (; cur < last; cur++) {
9034 GST_DEBUG_OBJECT (qtdemux,
9035 "fill sample %d: timestamp %" GST_TIME_FORMAT,
9036 (guint) (cur - samples),
9037 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
9038 cur->timestamp = stream->stts_time;
9044 /* sample sync, can be NULL */
9045 if (stream->stss_present == TRUE) {
9046 guint32 n_sample_syncs;
9048 n_sample_syncs = stream->n_sample_syncs;
9050 if (!n_sample_syncs) {
9051 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
9052 stream->all_keyframe = TRUE;
9054 for (i = stream->stss_index; i < n_sample_syncs; i++) {
9055 /* note that the first sample is index 1, not 0 */
9058 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
9060 if (G_LIKELY (index > 0 && index <= n_samples)) {
9062 samples[index].keyframe = TRUE;
9063 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
9064 /* and exit if we have enough samples */
9065 if (G_UNLIKELY (index >= n)) {
9072 stream->stss_index = i;
9075 /* stps marks partial sync frames like open GOP I-Frames */
9076 if (stream->stps_present == TRUE) {
9077 guint32 n_sample_partial_syncs;
9079 n_sample_partial_syncs = stream->n_sample_partial_syncs;
9081 /* if there are no entries, the stss table contains the real
9083 if (n_sample_partial_syncs) {
9084 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
9085 /* note that the first sample is index 1, not 0 */
9088 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
9090 if (G_LIKELY (index > 0 && index <= n_samples)) {
9092 samples[index].keyframe = TRUE;
9093 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
9094 /* and exit if we have enough samples */
9095 if (G_UNLIKELY (index >= n)) {
9102 stream->stps_index = i;
9106 /* no stss, all samples are keyframes */
9107 stream->all_keyframe = TRUE;
9108 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
9113 /* composition time to sample */
9114 if (stream->ctts_present == TRUE) {
9115 guint32 n_composition_times;
9117 gint32 ctts_soffset;
9119 /* Fill in the pts_offsets */
9121 n_composition_times = stream->n_composition_times;
9123 for (i = stream->ctts_index; i < n_composition_times; i++) {
9124 if (stream->ctts_sample_index >= stream->ctts_count
9125 || !stream->ctts_sample_index) {
9126 stream->ctts_count =
9127 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
9128 stream->ctts_soffset =
9129 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9130 stream->ctts_sample_index = 0;
9133 ctts_count = stream->ctts_count;
9134 ctts_soffset = stream->ctts_soffset;
9136 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
9137 cur->pts_offset = ctts_soffset;
9140 if (G_UNLIKELY (cur > last)) {
9142 stream->ctts_sample_index = j + 1;
9146 stream->ctts_sample_index = 0;
9147 stream->ctts_index++;
9151 stream->stbl_index = n;
9152 /* if index has been completely parsed, free data that is no-longer needed */
9153 if (n + 1 == stream->n_samples) {
9154 gst_qtdemux_stbl_free (stream);
9155 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
9156 if (qtdemux->pullbased) {
9157 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
9158 while (n + 1 == stream->n_samples)
9159 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
9163 GST_OBJECT_UNLOCK (qtdemux);
9170 GST_LOG_OBJECT (qtdemux,
9171 "Tried to parse up to sample %u but this sample has already been parsed",
9173 /* if fragmented, there may be more */
9174 if (qtdemux->fragmented && n == stream->stbl_index)
9176 GST_OBJECT_UNLOCK (qtdemux);
9182 GST_LOG_OBJECT (qtdemux,
9183 "Tried to parse up to sample %u but there are only %u samples", n + 1,
9185 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9186 (_("This file is corrupt and cannot be played.")), (NULL));
9191 GST_OBJECT_UNLOCK (qtdemux);
9192 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9193 (_("This file is corrupt and cannot be played.")), (NULL));
9198 /* collect all segment info for @stream.
9201 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
9205 /* accept edts if they contain gaps at start and there is only
9206 * one media segment */
9207 gboolean allow_pushbased_edts = TRUE;
9208 gint media_segments_count = 0;
9210 /* parse and prepare segment info from the edit list */
9211 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
9212 stream->n_segments = 0;
9213 stream->segments = NULL;
9214 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
9217 gint i, count, entry_size;
9220 const guint8 *buffer;
9224 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
9225 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
9228 buffer = elst->data;
9230 size = QT_UINT32 (buffer);
9231 /* version, flags, n_segments */
9233 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
9236 version = QT_UINT8 (buffer + 8);
9237 entry_size = (version == 1) ? 20 : 12;
9239 n_segments = QT_UINT32 (buffer + 12);
9241 if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
9242 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
9246 /* we might allocate a bit too much, at least allocate 1 segment */
9247 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
9249 /* segments always start from 0 */
9254 for (i = 0; i < n_segments; i++) {
9257 gboolean time_valid = TRUE;
9258 QtDemuxSegment *segment;
9260 GstClockTime media_start = GST_CLOCK_TIME_NONE;
9263 media_time = QT_UINT64 (buffer + 8);
9264 duration = QT_UINT64 (buffer);
9265 if (media_time == G_MAXUINT64)
9268 media_time = QT_UINT32 (buffer + 4);
9269 duration = QT_UINT32 (buffer);
9270 if (media_time == G_MAXUINT32)
9275 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
9277 segment = &stream->segments[count++];
9279 /* time and duration expressed in global timescale */
9280 segment->time = stime;
9281 /* add non scaled values so we don't cause roundoff errors */
9282 if (duration || media_start == GST_CLOCK_TIME_NONE) {
9284 stime = QTTIME_TO_GSTTIME (qtdemux, time);
9285 segment->duration = stime - segment->time;
9287 /* zero duration does not imply media_start == media_stop
9288 * but, only specify media_start.*/
9289 stime = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
9290 if (GST_CLOCK_TIME_IS_VALID (stime) && time_valid
9291 && stime >= media_start) {
9292 segment->duration = stime - media_start;
9294 segment->duration = GST_CLOCK_TIME_NONE;
9297 segment->stop_time = stime;
9299 segment->trak_media_start = media_time;
9300 /* media_time expressed in stream timescale */
9302 segment->media_start = media_start;
9303 segment->media_stop = segment->media_start + segment->duration;
9304 media_segments_count++;
9306 segment->media_start = GST_CLOCK_TIME_NONE;
9307 segment->media_stop = GST_CLOCK_TIME_NONE;
9309 rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
9311 if (rate_int <= 1) {
9312 /* 0 is not allowed, some programs write 1 instead of the floating point
9314 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
9318 segment->rate = rate_int / 65536.0;
9321 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
9322 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
9323 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
9324 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
9325 i, GST_TIME_ARGS (segment->time),
9326 GST_TIME_ARGS (segment->duration),
9327 GST_TIME_ARGS (segment->media_start), media_time,
9328 GST_TIME_ARGS (segment->media_stop),
9329 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
9331 if (segment->stop_time > qtdemux->segment.stop) {
9332 GST_WARNING_OBJECT (qtdemux, "Segment %d "
9333 " extends to %" GST_TIME_FORMAT
9334 " past the end of the file duration %" GST_TIME_FORMAT
9335 " it will be truncated", i, GST_TIME_ARGS (segment->stop_time),
9336 GST_TIME_ARGS (qtdemux->segment.stop));
9337 qtdemux->segment.stop = segment->stop_time;
9340 buffer += entry_size;
9342 GST_DEBUG_OBJECT (qtdemux, "found %d segments", count);
9343 stream->n_segments = count;
9344 if (media_segments_count != 1)
9345 allow_pushbased_edts = FALSE;
9349 /* push based does not handle segments, so act accordingly here,
9350 * and warn if applicable */
9351 if (!qtdemux->pullbased && !allow_pushbased_edts) {
9352 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
9353 /* remove and use default one below, we stream like it anyway */
9354 g_free (stream->segments);
9355 stream->segments = NULL;
9356 stream->n_segments = 0;
9359 /* no segments, create one to play the complete trak */
9360 if (stream->n_segments == 0) {
9361 GstClockTime stream_duration =
9362 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
9364 if (stream->segments == NULL)
9365 stream->segments = g_new (QtDemuxSegment, 1);
9367 /* represent unknown our way */
9368 if (stream_duration == 0)
9369 stream_duration = GST_CLOCK_TIME_NONE;
9371 stream->segments[0].time = 0;
9372 stream->segments[0].stop_time = stream_duration;
9373 stream->segments[0].duration = stream_duration;
9374 stream->segments[0].media_start = 0;
9375 stream->segments[0].media_stop = stream_duration;
9376 stream->segments[0].rate = 1.0;
9377 stream->segments[0].trak_media_start = 0;
9379 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
9380 GST_TIME_ARGS (stream_duration));
9381 stream->n_segments = 1;
9382 stream->dummy_segment = TRUE;
9384 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
9390 * Parses the stsd atom of a svq3 trak looking for
9391 * the SMI and gama atoms.
9394 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
9395 const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
9397 const guint8 *_gamma = NULL;
9398 GstBuffer *_seqh = NULL;
9399 const guint8 *stsd_data = stsd_entry_data;
9400 guint32 length = QT_UINT32 (stsd_data);
9404 GST_WARNING_OBJECT (qtdemux, "stsd too short");
9410 version = QT_UINT16 (stsd_data);
9415 while (length > 8) {
9416 guint32 fourcc, size;
9418 size = QT_UINT32 (stsd_data);
9419 fourcc = QT_FOURCC (stsd_data + 4);
9420 data = stsd_data + 8;
9423 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
9424 "svq3 atom parsing");
9433 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
9434 " for gama atom, expected 12", size);
9439 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
9441 if (_seqh != NULL) {
9442 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
9443 " found, ignoring");
9445 seqh_size = QT_UINT32 (data + 4);
9446 if (seqh_size > 0) {
9447 _seqh = gst_buffer_new_and_alloc (seqh_size);
9448 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
9455 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
9456 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
9460 if (size <= length) {
9466 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
9469 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
9470 G_GUINT16_FORMAT, version);
9481 gst_buffer_unref (_seqh);
9486 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
9493 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
9494 * atom that might contain a 'data' atom with the rtsp uri.
9495 * This case was reported in bug #597497, some info about
9496 * the hndl atom can be found in TN1195
9498 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
9499 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
9502 guint32 dref_num_entries = 0;
9503 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
9504 gst_byte_reader_skip (&dref, 4) &&
9505 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
9508 /* search dref entries for hndl atom */
9509 for (i = 0; i < dref_num_entries; i++) {
9510 guint32 size = 0, type;
9511 guint8 string_len = 0;
9512 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
9513 qt_atom_parser_get_fourcc (&dref, &type)) {
9514 if (type == FOURCC_hndl) {
9515 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
9517 /* skip data reference handle bytes and the
9518 * following pascal string and some extra 4
9519 * bytes I have no idea what are */
9520 if (!gst_byte_reader_skip (&dref, 4) ||
9521 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
9522 !gst_byte_reader_skip (&dref, string_len + 4)) {
9523 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
9527 /* iterate over the atoms to find the data atom */
9528 while (gst_byte_reader_get_remaining (&dref) >= 8) {
9532 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
9533 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
9534 if (atom_type == FOURCC_data) {
9535 const guint8 *uri_aux = NULL;
9537 /* found the data atom that might contain the rtsp uri */
9538 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
9539 "hndl atom, interpreting it as an URI");
9540 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
9542 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
9543 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
9545 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
9546 "didn't contain a rtsp address");
9548 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
9553 /* skipping to the next entry */
9554 if (!gst_byte_reader_skip (&dref, atom_size - 8))
9557 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
9564 /* skip to the next entry */
9565 if (!gst_byte_reader_skip (&dref, size - 8))
9568 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
9571 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
9577 #define AMR_NB_ALL_MODES 0x81ff
9578 #define AMR_WB_ALL_MODES 0x83ff
9580 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
9582 /* The 'damr' atom is of the form:
9584 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
9585 * 32 b 8 b 16 b 8 b 8 b
9587 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
9588 * represents the highest mode used in the stream (and thus the maximum
9589 * bitrate), with a couple of special cases as seen below.
9592 /* Map of frame type ID -> bitrate */
9593 static const guint nb_bitrates[] = {
9594 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
9596 static const guint wb_bitrates[] = {
9597 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
9603 gst_buffer_map (buf, &map, GST_MAP_READ);
9605 if (map.size != 0x11) {
9606 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
9610 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
9611 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
9612 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
9616 mode_set = QT_UINT16 (map.data + 13);
9618 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
9619 max_mode = 7 + (wb ? 1 : 0);
9621 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
9622 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
9624 if (max_mode == -1) {
9625 GST_DEBUG ("No mode indication was found (mode set) = %x",
9630 gst_buffer_unmap (buf, &map);
9631 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
9634 gst_buffer_unmap (buf, &map);
9639 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
9640 GstByteReader * reader, guint32 * matrix, const gchar * atom)
9643 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
9649 if (gst_byte_reader_get_remaining (reader) < 36)
9652 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
9653 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
9654 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
9655 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
9656 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
9657 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
9658 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
9659 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
9660 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
9662 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
9663 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
9664 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
9666 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
9667 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
9669 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
9670 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
9677 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
9678 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
9685 * This macro will only compare value abdegh, it expects cfi to have already
9688 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
9689 (m)[3] == (d << 16) && (m)[4] == (e << 16))
9691 /* only handle the cases where the last column has standard values */
9692 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
9693 const gchar *rotation_tag = NULL;
9695 /* no rotation needed */
9696 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
9698 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
9699 rotation_tag = "rotate-90";
9700 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
9701 rotation_tag = "rotate-180";
9702 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
9703 rotation_tag = "rotate-270";
9705 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9708 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
9710 if (rotation_tag != NULL) {
9711 if (*taglist == NULL)
9712 *taglist = gst_tag_list_new_empty ();
9713 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
9714 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
9717 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9721 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
9722 * protected streams (sinf, frma, schm and schi); if the protection scheme is
9723 * Common Encryption (cenc), the function will also parse the tenc box (defined
9724 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
9725 * (typically an enc[v|a|t|s] sample entry); the function will set
9726 * @original_fmt to the fourcc of the original unencrypted stream format.
9727 * Returns TRUE if successful; FALSE otherwise. */
9729 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
9730 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
9737 g_return_val_if_fail (qtdemux != NULL, FALSE);
9738 g_return_val_if_fail (stream != NULL, FALSE);
9739 g_return_val_if_fail (container != NULL, FALSE);
9740 g_return_val_if_fail (original_fmt != NULL, FALSE);
9742 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
9743 if (G_UNLIKELY (!sinf)) {
9744 if (stream->protection_scheme_type == FOURCC_cenc) {
9745 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
9746 "mandatory for Common Encryption");
9752 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
9753 if (G_UNLIKELY (!frma)) {
9754 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
9758 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
9759 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
9760 GST_FOURCC_ARGS (*original_fmt));
9762 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
9764 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
9767 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
9768 stream->protection_scheme_version =
9769 QT_UINT32 ((const guint8 *) schm->data + 16);
9771 GST_DEBUG_OBJECT (qtdemux,
9772 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
9773 "protection_scheme_version: %#010x",
9774 GST_FOURCC_ARGS (stream->protection_scheme_type),
9775 stream->protection_scheme_version);
9777 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
9779 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
9782 if (stream->protection_scheme_type == FOURCC_cenc) {
9783 QtDemuxCencSampleSetInfo *info;
9785 const guint8 *tenc_data;
9786 guint32 isEncrypted;
9788 const guint8 *default_kid;
9791 if (G_UNLIKELY (!stream->protection_scheme_info))
9792 stream->protection_scheme_info =
9793 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
9795 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
9797 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
9799 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
9800 "which is mandatory for Common Encryption");
9803 tenc_data = (const guint8 *) tenc->data + 12;
9804 isEncrypted = QT_UINT24 (tenc_data);
9805 iv_size = QT_UINT8 (tenc_data + 3);
9806 default_kid = (tenc_data + 4);
9807 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
9808 gst_buffer_fill (kid_buf, 0, default_kid, 16);
9809 if (info->default_properties)
9810 gst_structure_free (info->default_properties);
9811 info->default_properties =
9812 gst_structure_new ("application/x-cenc",
9813 "iv_size", G_TYPE_UINT, iv_size,
9814 "encrypted", G_TYPE_BOOLEAN, (isEncrypted == 1),
9815 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
9816 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
9817 "is_encrypted=%u, iv_size=%u", isEncrypted, iv_size);
9818 gst_buffer_unref (kid_buf);
9824 * With each track we associate a new QtDemuxStream that contains all the info
9826 * traks that do not decode to something (like strm traks) will not have a pad.
9829 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
9846 QtDemuxStream *stream = NULL;
9847 gboolean new_stream = FALSE;
9848 const guint8 *stsd_data;
9849 const guint8 *stsd_entry_data;
9850 guint remaining_stsd_len;
9851 guint stsd_entry_count;
9853 guint16 lang_code; /* quicktime lang code or packed iso code */
9855 guint32 tkhd_flags = 0;
9856 guint8 tkhd_version = 0;
9857 guint32 w = 0, h = 0;
9858 guint value_size, stsd_len, len;
9862 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
9864 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
9865 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
9866 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
9869 /* pick between 64 or 32 bits */
9870 value_size = tkhd_version == 1 ? 8 : 4;
9871 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
9872 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
9875 if (!qtdemux->got_moov) {
9876 if (qtdemux_find_stream (qtdemux, track_id))
9877 goto existing_stream;
9878 stream = _create_stream (qtdemux, track_id);
9879 stream->track_id = track_id;
9882 stream = qtdemux_find_stream (qtdemux, track_id);
9884 GST_WARNING_OBJECT (qtdemux, "Stream not found, going to ignore it");
9888 /* reset reused stream */
9889 gst_qtdemux_stream_reset (stream);
9891 /* need defaults for fragments */
9892 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
9894 if ((tkhd_flags & 1) == 0)
9895 stream->disabled = TRUE;
9897 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
9898 tkhd_version, tkhd_flags, stream->track_id);
9900 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
9903 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
9904 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
9905 if (qtdemux->major_brand != FOURCC_mjp2 ||
9906 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
9910 len = QT_UINT32 ((guint8 *) mdhd->data);
9911 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
9912 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
9913 if (version == 0x01000000) {
9916 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
9917 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
9918 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
9922 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
9923 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
9924 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
9927 if (lang_code < 0x400) {
9928 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
9929 } else if (lang_code == 0x7fff) {
9930 stream->lang_id[0] = 0; /* unspecified */
9932 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
9933 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
9934 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
9935 stream->lang_id[3] = 0;
9938 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
9940 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
9942 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
9943 lang_code, stream->lang_id);
9945 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
9948 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
9949 /* chapters track reference */
9950 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
9952 gsize length = GST_READ_UINT32_BE (chap->data);
9953 if (qtdemux->chapters_track_id)
9954 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
9957 qtdemux->chapters_track_id =
9958 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
9963 /* fragmented files may have bogus duration in moov */
9964 if (!qtdemux->fragmented &&
9965 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
9966 guint64 tdur1, tdur2;
9968 /* don't overflow */
9969 tdur1 = stream->timescale * (guint64) qtdemux->duration;
9970 tdur2 = qtdemux->timescale * (guint64) stream->duration;
9973 * some of those trailers, nowadays, have prologue images that are
9974 * themselves video tracks as well. I haven't really found a way to
9975 * identify those yet, except for just looking at their duration. */
9976 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
9977 GST_WARNING_OBJECT (qtdemux,
9978 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
9979 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
9980 "found, assuming preview image or something; skipping track",
9981 stream->duration, stream->timescale, qtdemux->duration,
9982 qtdemux->timescale);
9984 gst_qtdemux_stream_free (stream);
9989 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
9992 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
9993 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
9995 len = QT_UINT32 ((guint8 *) hdlr->data);
9997 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
9998 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
9999 GST_FOURCC_ARGS (stream->subtype));
10001 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
10004 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
10007 /*parse svmi header if existing */
10008 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
10010 len = QT_UINT32 ((guint8 *) svmi->data);
10011 version = QT_UINT32 ((guint8 *) svmi->data + 8);
10013 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
10014 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
10015 guint8 frame_type, frame_layout;
10017 /* MPEG-A stereo video */
10018 if (qtdemux->major_brand == FOURCC_ss02)
10019 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
10021 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
10022 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
10023 switch (frame_type) {
10025 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
10028 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
10031 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
10034 /* mode 3 is primary/secondary view sequence, ie
10035 * left/right views in separate tracks. See section 7.2
10036 * of ISO/IEC 23000-11:2009 */
10037 GST_FIXME_OBJECT (qtdemux,
10038 "Implement stereo video in separate streams");
10041 if ((frame_layout & 0x1) == 0)
10042 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
10044 GST_LOG_OBJECT (qtdemux,
10045 "StereoVideo: composition type: %u, is_left_first: %u",
10046 frame_type, frame_layout);
10047 stream->multiview_mode = mode;
10048 stream->multiview_flags = flags;
10052 /* parse rest of tkhd */
10053 if (stream->subtype == FOURCC_vide) {
10056 /* version 1 uses some 64-bit ints */
10057 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
10060 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
10063 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
10064 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
10067 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
10068 &stream->stream_tags);
10072 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
10074 stsd_data = (const guint8 *) stsd->data;
10076 /* stsd should at least have one entry */
10077 stsd_len = QT_UINT32 (stsd_data);
10078 if (stsd_len < 24) {
10079 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
10080 if (stream->subtype == FOURCC_vivo) {
10082 gst_qtdemux_stream_free (stream);
10089 stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
10090 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
10091 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
10092 GST_LOG_OBJECT (qtdemux, "stsd entry count: %u", stsd_entry_count);
10094 stsd_entry_data = stsd_data + 16;
10095 remaining_stsd_len = stsd_len - 16;
10096 for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
10098 gchar *codec = NULL;
10099 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
10101 /* and that entry should fit within stsd */
10102 len = QT_UINT32 (stsd_entry_data);
10103 if (len > remaining_stsd_len)
10106 entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
10107 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
10108 GST_FOURCC_ARGS (entry->fourcc));
10109 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
10111 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
10112 goto error_encrypted;
10114 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
10115 /* FIXME this looks wrong, there might be multiple children
10116 * with the same type */
10117 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
10118 stream->protected = TRUE;
10119 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
10120 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
10123 if (stream->subtype == FOURCC_vide) {
10128 gint depth, palette_size, palette_count;
10129 guint32 *palette_data = NULL;
10131 entry->sampled = TRUE;
10133 stream->display_width = w >> 16;
10134 stream->display_height = h >> 16;
10137 if (len < 86) /* TODO verify */
10140 entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
10141 entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
10142 entry->fps_n = 0; /* this is filled in later */
10143 entry->fps_d = 0; /* this is filled in later */
10144 entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
10145 entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
10147 /* if color_table_id is 0, ctab atom must follow; however some files
10148 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
10149 * if color table is not present we'll correct the value */
10150 if (entry->color_table_id == 0 &&
10152 || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
10153 entry->color_table_id = -1;
10156 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
10157 entry->width, entry->height, entry->bits_per_sample,
10158 entry->color_table_id);
10160 depth = entry->bits_per_sample;
10162 /* more than 32 bits means grayscale */
10163 gray = (depth > 32);
10164 /* low 32 bits specify the depth */
10167 /* different number of palette entries is determined by depth. */
10169 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
10170 palette_count = (1 << depth);
10171 palette_size = palette_count * 4;
10173 if (entry->color_table_id) {
10174 switch (palette_count) {
10178 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
10181 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
10186 g_memdup (ff_qt_grayscale_palette_16, palette_size);
10188 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
10193 g_memdup (ff_qt_grayscale_palette_256, palette_size);
10195 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
10198 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
10199 (_("The video in this file might not play correctly.")),
10200 ("unsupported palette depth %d", depth));
10204 gint i, j, start, end;
10210 start = QT_UINT32 (stsd_entry_data + offset + 70);
10211 palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
10212 end = QT_UINT16 (stsd_entry_data + offset + 76);
10214 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
10215 start, end, palette_count);
10222 if (len < 94 + (end - start) * 8)
10225 /* palette is always the same size */
10226 palette_data = g_malloc0 (256 * 4);
10227 palette_size = 256 * 4;
10229 for (j = 0, i = start; i <= end; j++, i++) {
10230 guint32 a, r, g, b;
10232 a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
10233 r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
10234 g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
10235 b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
10237 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
10238 (g & 0xff00) | (b >> 8);
10243 gst_caps_unref (entry->caps);
10246 qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
10248 if (G_UNLIKELY (!entry->caps)) {
10249 g_free (palette_data);
10250 goto unknown_stream;
10254 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
10255 GST_TAG_VIDEO_CODEC, codec, NULL);
10260 if (palette_data) {
10263 if (entry->rgb8_palette)
10264 gst_memory_unref (entry->rgb8_palette);
10265 entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
10266 palette_data, palette_size, 0, palette_size, palette_data, g_free);
10268 s = gst_caps_get_structure (entry->caps, 0);
10270 /* non-raw video has a palette_data property. raw video has the palette as
10271 * an extra plane that we append to the output buffers before we push
10273 if (!gst_structure_has_name (s, "video/x-raw")) {
10274 GstBuffer *palette;
10276 palette = gst_buffer_new ();
10277 gst_buffer_append_memory (palette, entry->rgb8_palette);
10278 entry->rgb8_palette = NULL;
10280 gst_caps_set_simple (entry->caps, "palette_data",
10281 GST_TYPE_BUFFER, palette, NULL);
10282 gst_buffer_unref (palette);
10284 } else if (palette_count != 0) {
10285 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
10286 (NULL), ("Unsupported palette depth %d", depth));
10289 GST_LOG_OBJECT (qtdemux, "frame count: %u",
10290 QT_UINT16 (stsd_entry_data + offset + 32));
10296 /* pick 'the' stsd child */
10297 mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10298 if (!stream->protected) {
10299 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
10303 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) {
10309 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
10310 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
10311 colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
10312 fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
10316 const guint8 *pasp_data = (const guint8 *) pasp->data;
10317 gint len = QT_UINT32 (pasp_data);
10320 CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
10321 CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
10323 CUR_STREAM (stream)->par_w = 0;
10324 CUR_STREAM (stream)->par_h = 0;
10327 CUR_STREAM (stream)->par_w = 0;
10328 CUR_STREAM (stream)->par_h = 0;
10332 const guint8 *fiel_data = (const guint8 *) fiel->data;
10333 gint len = QT_UINT32 (fiel_data);
10336 CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
10337 CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
10342 const guint8 *colr_data = (const guint8 *) colr->data;
10343 gint len = QT_UINT32 (colr_data);
10345 if (len == 19 || len == 18) {
10346 guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
10348 if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
10349 guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
10350 guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
10351 guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
10352 gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
10354 switch (primaries) {
10356 CUR_STREAM (stream)->colorimetry.primaries =
10357 GST_VIDEO_COLOR_PRIMARIES_BT709;
10360 CUR_STREAM (stream)->colorimetry.primaries =
10361 GST_VIDEO_COLOR_PRIMARIES_BT470BG;
10364 CUR_STREAM (stream)->colorimetry.primaries =
10365 GST_VIDEO_COLOR_PRIMARIES_SMPTE170M;
10368 CUR_STREAM (stream)->colorimetry.primaries =
10369 GST_VIDEO_COLOR_PRIMARIES_BT2020;
10375 switch (transfer_function) {
10377 CUR_STREAM (stream)->colorimetry.transfer =
10378 GST_VIDEO_TRANSFER_BT709;
10381 CUR_STREAM (stream)->colorimetry.transfer =
10382 GST_VIDEO_TRANSFER_SMPTE240M;
10390 CUR_STREAM (stream)->colorimetry.matrix =
10391 GST_VIDEO_COLOR_MATRIX_BT709;
10394 CUR_STREAM (stream)->colorimetry.matrix =
10395 GST_VIDEO_COLOR_MATRIX_BT601;
10398 CUR_STREAM (stream)->colorimetry.matrix =
10399 GST_VIDEO_COLOR_MATRIX_SMPTE240M;
10402 CUR_STREAM (stream)->colorimetry.matrix =
10403 GST_VIDEO_COLOR_MATRIX_BT2020;
10409 CUR_STREAM (stream)->colorimetry.range =
10410 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
10411 GST_VIDEO_COLOR_RANGE_16_235;
10413 GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
10416 GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
10421 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
10422 stream->stream_tags);
10429 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10430 const guint8 *avc_data = stsd_entry_data + 0x56;
10433 while (len >= 0x8) {
10436 if (QT_UINT32 (avc_data) <= len)
10437 size = QT_UINT32 (avc_data) - 0x8;
10442 /* No real data, so break out */
10445 switch (QT_FOURCC (avc_data + 0x4)) {
10448 /* parse, if found */
10451 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
10453 /* First 4 bytes are the length of the atom, the next 4 bytes
10454 * are the fourcc, the next 1 byte is the version, and the
10455 * subsequent bytes are profile_tier_level structure like data. */
10456 gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
10457 avc_data + 8 + 1, size - 1);
10458 buf = gst_buffer_new_and_alloc (size);
10459 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
10460 gst_caps_set_simple (entry->caps,
10461 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10462 gst_buffer_unref (buf);
10470 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
10472 /* First 4 bytes are the length of the atom, the next 4 bytes
10473 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
10474 * next 1 byte is the version, and the
10475 * subsequent bytes are sequence parameter set like data. */
10477 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
10479 gst_codec_utils_h264_caps_set_level_and_profile
10480 (entry->caps, avc_data + 8 + 40 + 1, size - 1);
10482 buf = gst_buffer_new_and_alloc (size);
10483 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
10484 gst_caps_set_simple (entry->caps,
10485 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10486 gst_buffer_unref (buf);
10492 guint avg_bitrate, max_bitrate;
10494 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
10498 max_bitrate = QT_UINT32 (avc_data + 0xc);
10499 avg_bitrate = QT_UINT32 (avc_data + 0x10);
10501 if (!max_bitrate && !avg_bitrate)
10504 /* Some muxers seem to swap the average and maximum bitrates
10505 * (I'm looking at you, YouTube), so we swap for sanity. */
10506 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
10507 guint temp = avg_bitrate;
10509 avg_bitrate = max_bitrate;
10510 max_bitrate = temp;
10513 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
10514 gst_tag_list_add (stream->stream_tags,
10515 GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
10516 max_bitrate, NULL);
10518 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
10519 gst_tag_list_add (stream->stream_tags,
10520 GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
10532 avc_data += size + 8;
10541 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10542 const guint8 *hevc_data = stsd_entry_data + 0x56;
10545 while (len >= 0x8) {
10548 if (QT_UINT32 (hevc_data) <= len)
10549 size = QT_UINT32 (hevc_data) - 0x8;
10554 /* No real data, so break out */
10557 switch (QT_FOURCC (hevc_data + 0x4)) {
10560 /* parse, if found */
10563 GST_DEBUG_OBJECT (qtdemux, "found hvcC codec_data in stsd");
10565 /* First 4 bytes are the length of the atom, the next 4 bytes
10566 * are the fourcc, the next 1 byte is the version, and the
10567 * subsequent bytes are sequence parameter set like data. */
10568 gst_codec_utils_h265_caps_set_level_tier_and_profile
10569 (entry->caps, hevc_data + 8 + 1, size - 1);
10571 buf = gst_buffer_new_and_alloc (size);
10572 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
10573 gst_caps_set_simple (entry->caps,
10574 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10575 gst_buffer_unref (buf);
10582 hevc_data += size + 8;
10595 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
10596 GST_FOURCC_ARGS (fourcc));
10598 /* codec data might be in glbl extension atom */
10600 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
10606 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
10608 len = QT_UINT32 (data);
10611 buf = gst_buffer_new_and_alloc (len);
10612 gst_buffer_fill (buf, 0, data + 8, len);
10613 gst_caps_set_simple (entry->caps,
10614 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10615 gst_buffer_unref (buf);
10622 /* see annex I of the jpeg2000 spec */
10623 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
10624 const guint8 *data;
10625 const gchar *colorspace = NULL;
10627 guint32 ncomp_map = 0;
10628 gint32 *comp_map = NULL;
10629 guint32 nchan_def = 0;
10630 gint32 *chan_def = NULL;
10632 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
10633 /* some required atoms */
10634 mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10637 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
10641 /* number of components; redundant with info in codestream, but useful
10643 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
10644 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
10646 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
10648 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
10651 GST_DEBUG_OBJECT (qtdemux, "found colr");
10652 /* extract colour space info */
10653 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
10654 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
10656 colorspace = "sRGB";
10659 colorspace = "GRAY";
10662 colorspace = "sYUV";
10670 /* colr is required, and only values 16, 17, and 18 are specified,
10671 so error if we have no colorspace */
10674 /* extract component mapping */
10675 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
10677 guint32 cmap_len = 0;
10679 cmap_len = QT_UINT32 (cmap->data);
10680 if (cmap_len >= 8) {
10681 /* normal box, subtract off header */
10683 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
10684 if (cmap_len % 4 == 0) {
10685 ncomp_map = (cmap_len / 4);
10686 comp_map = g_new0 (gint32, ncomp_map);
10687 for (i = 0; i < ncomp_map; i++) {
10690 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
10691 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
10692 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
10693 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
10698 /* extract channel definitions */
10699 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
10701 guint32 cdef_len = 0;
10703 cdef_len = QT_UINT32 (cdef->data);
10704 if (cdef_len >= 10) {
10705 /* normal box, subtract off header and len */
10707 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
10708 if (cdef_len % 6 == 0) {
10709 nchan_def = (cdef_len / 6);
10710 chan_def = g_new0 (gint32, nchan_def);
10711 for (i = 0; i < nchan_def; i++)
10713 for (i = 0; i < nchan_def; i++) {
10714 guint16 cn, typ, asoc;
10715 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
10716 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
10717 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
10718 if (cn < nchan_def) {
10721 chan_def[cn] = asoc;
10724 chan_def[cn] = 0; /* alpha */
10727 chan_def[cn] = -typ;
10735 gst_caps_set_simple (entry->caps,
10736 "num-components", G_TYPE_INT, ncomp, NULL);
10737 gst_caps_set_simple (entry->caps,
10738 "colorspace", G_TYPE_STRING, colorspace, NULL);
10741 GValue arr = { 0, };
10742 GValue elt = { 0, };
10744 g_value_init (&arr, GST_TYPE_ARRAY);
10745 g_value_init (&elt, G_TYPE_INT);
10746 for (i = 0; i < ncomp_map; i++) {
10747 g_value_set_int (&elt, comp_map[i]);
10748 gst_value_array_append_value (&arr, &elt);
10750 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
10751 "component-map", &arr);
10752 g_value_unset (&elt);
10753 g_value_unset (&arr);
10758 GValue arr = { 0, };
10759 GValue elt = { 0, };
10761 g_value_init (&arr, GST_TYPE_ARRAY);
10762 g_value_init (&elt, G_TYPE_INT);
10763 for (i = 0; i < nchan_def; i++) {
10764 g_value_set_int (&elt, chan_def[i]);
10765 gst_value_array_append_value (&arr, &elt);
10767 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
10768 "channel-definitions", &arr);
10769 g_value_unset (&elt);
10770 g_value_unset (&arr);
10774 /* some optional atoms */
10775 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
10776 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
10778 /* indicate possible fields in caps */
10780 data = (guint8 *) field->data + 8;
10782 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
10783 (gint) * data, NULL);
10785 /* add codec_data if provided */
10790 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
10791 data = prefix->data;
10792 len = QT_UINT32 (data);
10795 buf = gst_buffer_new_and_alloc (len);
10796 gst_buffer_fill (buf, 0, data + 8, len);
10797 gst_caps_set_simple (entry->caps,
10798 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10799 gst_buffer_unref (buf);
10808 GstBuffer *seqh = NULL;
10809 const guint8 *gamma_data = NULL;
10810 gint len = QT_UINT32 (stsd_data); /* FIXME review - why put the whole stsd in codec data? */
10812 qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
10815 gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
10816 QT_FP32 (gamma_data), NULL);
10819 /* sorry for the bad name, but we don't know what this is, other
10820 * than its own fourcc */
10821 gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
10823 gst_buffer_unref (seqh);
10826 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
10827 buf = gst_buffer_new_and_alloc (len);
10828 gst_buffer_fill (buf, 0, stsd_data, len);
10829 gst_caps_set_simple (entry->caps,
10830 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10831 gst_buffer_unref (buf);
10836 /* https://developer.apple.com/standards/qtff-2001.pdf,
10837 * page 92, "Video Sample Description", under table 3.1 */
10840 const gint compressor_offset =
10841 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
10842 const gint min_size = compressor_offset + 32 + 2 + 2;
10845 guint16 color_table_id = 0;
10848 GST_DEBUG_OBJECT (qtdemux, "found jpeg");
10850 /* recover information on interlaced/progressive */
10851 jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
10855 len = QT_UINT32 (jpeg->data);
10856 GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
10858 if (len >= min_size) {
10859 gst_byte_reader_init (&br, jpeg->data, len);
10861 gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
10862 gst_byte_reader_get_uint16_le (&br, &color_table_id);
10863 if (color_table_id != 0) {
10864 /* the spec says there can be concatenated chunks in the data, and we want
10865 * to find one called field. Walk through them. */
10866 gint offset = min_size;
10867 while (offset + 8 < len) {
10868 guint32 size = 0, tag;
10869 ok = gst_byte_reader_get_uint32_le (&br, &size);
10870 ok &= gst_byte_reader_get_uint32_le (&br, &tag);
10871 if (!ok || size < 8) {
10872 GST_WARNING_OBJECT (qtdemux,
10873 "Failed to walk optional chunk list");
10876 GST_DEBUG_OBJECT (qtdemux,
10877 "Found optional %4.4s chunk, size %u",
10878 (const char *) &tag, size);
10879 if (tag == FOURCC_fiel) {
10880 guint8 n_fields = 0, ordering = 0;
10881 gst_byte_reader_get_uint8 (&br, &n_fields);
10882 gst_byte_reader_get_uint8 (&br, &ordering);
10883 if (n_fields == 1 || n_fields == 2) {
10884 GST_DEBUG_OBJECT (qtdemux,
10885 "Found fiel tag with %u fields, ordering %u",
10886 n_fields, ordering);
10888 gst_caps_set_simple (CUR_STREAM (stream)->caps,
10889 "interlace-mode", G_TYPE_STRING, "interleaved",
10892 GST_WARNING_OBJECT (qtdemux,
10893 "Found fiel tag with invalid fields (%u)", n_fields);
10899 GST_DEBUG_OBJECT (qtdemux,
10900 "Color table ID is 0, not trying to get interlacedness");
10903 GST_WARNING_OBJECT (qtdemux,
10904 "Length of jpeg chunk is too small, not trying to get interlacedness");
10912 gst_caps_set_simple (entry->caps,
10913 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 66),
10919 GNode *xith, *xdxt;
10921 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
10922 xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10926 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
10930 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
10931 /* collect the headers and store them in a stream list so that we can
10932 * send them out first */
10933 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
10943 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
10944 ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10947 ovc1_data = ovc1->data;
10948 ovc1_len = QT_UINT32 (ovc1_data);
10949 if (ovc1_len <= 198) {
10950 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
10953 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
10954 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
10955 gst_caps_set_simple (entry->caps,
10956 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10957 gst_buffer_unref (buf);
10962 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10963 const guint8 *vc1_data = stsd_entry_data + 0x56;
10969 if (QT_UINT32 (vc1_data) <= len)
10970 size = QT_UINT32 (vc1_data) - 8;
10975 /* No real data, so break out */
10978 switch (QT_FOURCC (vc1_data + 0x4)) {
10979 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
10983 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
10984 buf = gst_buffer_new_and_alloc (size);
10985 gst_buffer_fill (buf, 0, vc1_data + 8, size);
10986 gst_caps_set_simple (entry->caps,
10987 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10988 gst_buffer_unref (buf);
10995 vc1_data += size + 8;
11004 GST_INFO_OBJECT (qtdemux,
11005 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11006 GST_FOURCC_ARGS (fourcc), entry->caps);
11008 } else if (stream->subtype == FOURCC_soun) {
11010 int version, samplesize;
11011 guint16 compression_id;
11012 gboolean amrwb = FALSE;
11015 /* sample description entry (16) + sound sample description v0 (20) */
11019 version = QT_UINT32 (stsd_entry_data + offset);
11020 entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
11021 samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
11022 compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
11023 entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
11025 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
11026 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
11027 QT_UINT32 (stsd_entry_data + offset + 4));
11028 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
11029 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
11030 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
11031 GST_LOG_OBJECT (qtdemux, "packet size: %d",
11032 QT_UINT16 (stsd_entry_data + offset + 14));
11033 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
11035 if (compression_id == 0xfffe)
11036 entry->sampled = TRUE;
11038 /* first assume uncompressed audio */
11039 entry->bytes_per_sample = samplesize / 8;
11040 entry->samples_per_frame = entry->n_channels;
11041 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
11042 entry->samples_per_packet = entry->samples_per_frame;
11043 entry->bytes_per_packet = entry->bytes_per_sample;
11047 /* Yes, these have to be hard-coded */
11050 entry->samples_per_packet = 6;
11051 entry->bytes_per_packet = 1;
11052 entry->bytes_per_frame = 1 * entry->n_channels;
11053 entry->bytes_per_sample = 1;
11054 entry->samples_per_frame = 6 * entry->n_channels;
11059 entry->samples_per_packet = 3;
11060 entry->bytes_per_packet = 1;
11061 entry->bytes_per_frame = 1 * entry->n_channels;
11062 entry->bytes_per_sample = 1;
11063 entry->samples_per_frame = 3 * entry->n_channels;
11068 entry->samples_per_packet = 64;
11069 entry->bytes_per_packet = 34;
11070 entry->bytes_per_frame = 34 * entry->n_channels;
11071 entry->bytes_per_sample = 2;
11072 entry->samples_per_frame = 64 * entry->n_channels;
11078 entry->samples_per_packet = 1;
11079 entry->bytes_per_packet = 1;
11080 entry->bytes_per_frame = 1 * entry->n_channels;
11081 entry->bytes_per_sample = 1;
11082 entry->samples_per_frame = 1 * entry->n_channels;
11087 entry->samples_per_packet = 160;
11088 entry->bytes_per_packet = 33;
11089 entry->bytes_per_frame = 33 * entry->n_channels;
11090 entry->bytes_per_sample = 2;
11091 entry->samples_per_frame = 160 * entry->n_channels;
11098 if (version == 0x00010000) {
11099 /* sample description entry (16) + sound sample description v1 (20+16) */
11111 /* only parse extra decoding config for non-pcm audio */
11112 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
11113 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
11114 entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
11115 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
11117 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
11118 entry->samples_per_packet);
11119 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
11120 entry->bytes_per_packet);
11121 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
11122 entry->bytes_per_frame);
11123 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
11124 entry->bytes_per_sample);
11126 if (!entry->sampled && entry->bytes_per_packet) {
11127 entry->samples_per_frame = (entry->bytes_per_frame /
11128 entry->bytes_per_packet) * entry->samples_per_packet;
11129 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
11130 entry->samples_per_frame);
11135 } else if (version == 0x00020000) {
11142 /* sample description entry (16) + sound sample description v2 (56) */
11146 qtfp.val = QT_UINT64 (stsd_entry_data + offset + 4);
11147 entry->rate = qtfp.fp;
11148 entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
11150 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
11151 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
11152 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
11153 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
11154 QT_UINT32 (stsd_entry_data + offset + 20));
11155 GST_LOG_OBJECT (qtdemux, "format flags: %X",
11156 QT_UINT32 (stsd_entry_data + offset + 24));
11157 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
11158 QT_UINT32 (stsd_entry_data + offset + 28));
11159 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
11160 QT_UINT32 (stsd_entry_data + offset + 32));
11161 } else if (version != 0x00000) {
11162 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
11167 gst_caps_unref (entry->caps);
11169 entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
11170 stsd_entry_data + 32, len - 16, &codec);
11178 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
11180 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
11182 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
11184 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
11187 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
11188 gst_caps_set_simple (entry->caps,
11189 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE",
11196 const guint8 *owma_data;
11197 const gchar *codec_name = NULL;
11201 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
11202 /* FIXME this should also be gst_riff_strf_auds,
11203 * but the latter one is actually missing bits-per-sample :( */
11208 gint32 nSamplesPerSec;
11209 gint32 nAvgBytesPerSec;
11210 gint16 nBlockAlign;
11211 gint16 wBitsPerSample;
11214 WAVEFORMATEX *wfex;
11216 GST_DEBUG_OBJECT (qtdemux, "parse owma");
11217 owma_data = stsd_entry_data;
11218 owma_len = QT_UINT32 (owma_data);
11219 if (owma_len <= 54) {
11220 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
11223 wfex = (WAVEFORMATEX *) (owma_data + 36);
11224 buf = gst_buffer_new_and_alloc (owma_len - 54);
11225 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
11226 if (wfex->wFormatTag == 0x0161) {
11227 codec_name = "Windows Media Audio";
11229 } else if (wfex->wFormatTag == 0x0162) {
11230 codec_name = "Windows Media Audio 9 Pro";
11232 } else if (wfex->wFormatTag == 0x0163) {
11233 codec_name = "Windows Media Audio 9 Lossless";
11234 /* is that correct? gstffmpegcodecmap.c is missing it, but
11235 * fluendo codec seems to support it */
11239 gst_caps_set_simple (entry->caps,
11240 "codec_data", GST_TYPE_BUFFER, buf,
11241 "wmaversion", G_TYPE_INT, version,
11242 "block_align", G_TYPE_INT,
11243 GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
11244 GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
11245 GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
11246 GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
11247 gst_buffer_unref (buf);
11251 codec = g_strdup (codec_name);
11257 gint len = QT_UINT32 (stsd_entry_data) - offset;
11258 const guint8 *wfex_data = stsd_entry_data + offset;
11259 const gchar *codec_name = NULL;
11261 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
11262 /* FIXME this should also be gst_riff_strf_auds,
11263 * but the latter one is actually missing bits-per-sample :( */
11268 gint32 nSamplesPerSec;
11269 gint32 nAvgBytesPerSec;
11270 gint16 nBlockAlign;
11271 gint16 wBitsPerSample;
11276 /* FIXME: unify with similar wavformatex parsing code above */
11277 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
11283 if (QT_UINT32 (wfex_data) <= len)
11284 size = QT_UINT32 (wfex_data) - 8;
11289 /* No real data, so break out */
11292 switch (QT_FOURCC (wfex_data + 4)) {
11293 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
11295 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
11300 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
11301 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
11302 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
11303 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
11304 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
11305 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
11306 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
11308 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
11309 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
11310 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
11311 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
11312 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
11313 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
11315 if (wfex.wFormatTag == 0x0161) {
11316 codec_name = "Windows Media Audio";
11318 } else if (wfex.wFormatTag == 0x0162) {
11319 codec_name = "Windows Media Audio 9 Pro";
11321 } else if (wfex.wFormatTag == 0x0163) {
11322 codec_name = "Windows Media Audio 9 Lossless";
11323 /* is that correct? gstffmpegcodecmap.c is missing it, but
11324 * fluendo codec seems to support it */
11328 gst_caps_set_simple (entry->caps,
11329 "wmaversion", G_TYPE_INT, version,
11330 "block_align", G_TYPE_INT, wfex.nBlockAlign,
11331 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
11332 "width", G_TYPE_INT, wfex.wBitsPerSample,
11333 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
11335 if (size > wfex.cbSize) {
11338 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
11339 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
11340 size - wfex.cbSize);
11341 gst_caps_set_simple (entry->caps,
11342 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11343 gst_buffer_unref (buf);
11345 GST_WARNING_OBJECT (qtdemux, "no codec data");
11350 codec = g_strdup (codec_name);
11358 wfex_data += size + 8;
11364 const guint8 *opus_data;
11365 guint8 *channel_mapping = NULL;
11368 guint8 channel_mapping_family;
11369 guint8 stream_count;
11370 guint8 coupled_count;
11373 opus_data = stsd_entry_data;
11375 channels = GST_READ_UINT8 (opus_data + 45);
11376 rate = GST_READ_UINT32_LE (opus_data + 48);
11377 channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
11378 stream_count = GST_READ_UINT8 (opus_data + 55);
11379 coupled_count = GST_READ_UINT8 (opus_data + 56);
11381 if (channels > 0) {
11382 channel_mapping = g_malloc (channels * sizeof (guint8));
11383 for (i = 0; i < channels; i++)
11384 channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
11387 entry->caps = gst_codec_utils_opus_create_caps (rate, channels,
11388 channel_mapping_family, stream_count, coupled_count,
11400 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11401 GST_TAG_AUDIO_CODEC, codec, NULL);
11405 /* some bitrate info may have ended up in caps */
11406 s = gst_caps_get_structure (entry->caps, 0);
11407 gst_structure_get_int (s, "bitrate", &bitrate);
11409 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11410 GST_TAG_BITRATE, bitrate, NULL);
11413 mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11414 if (!stream->protected) {
11416 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) {
11420 if (stream->protected && fourcc == FOURCC_mp4a) {
11421 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) {
11425 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_mp4a) {
11433 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
11435 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
11437 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
11441 /* If the fourcc's bottom 16 bits gives 'sm', then the top
11442 16 bits is a byte-swapped wave-style codec identifier,
11443 and we can find a WAVE header internally to a 'wave' atom here.
11444 This can more clearly be thought of as 'ms' as the top 16 bits, and a
11445 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
11448 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
11449 if (len < offset + 20) {
11450 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
11452 guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
11453 const guint8 *data = stsd_entry_data + offset + 16;
11455 GNode *waveheadernode;
11457 wavenode = g_node_new ((guint8 *) data);
11458 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
11459 const guint8 *waveheader;
11462 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
11463 if (waveheadernode) {
11464 waveheader = (const guint8 *) waveheadernode->data;
11465 headerlen = QT_UINT32 (waveheader);
11467 if (headerlen > 8) {
11468 gst_riff_strf_auds *header = NULL;
11469 GstBuffer *headerbuf;
11475 headerbuf = gst_buffer_new_and_alloc (headerlen);
11476 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
11478 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
11479 headerbuf, &header, &extra)) {
11480 gst_caps_unref (entry->caps);
11481 /* FIXME: Need to do something with the channel reorder map */
11483 gst_riff_create_audio_caps (header->format, NULL, header,
11484 extra, NULL, NULL, NULL);
11487 gst_buffer_unref (extra);
11492 GST_DEBUG ("Didn't find waveheadernode for this codec");
11494 g_node_destroy (wavenode);
11497 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11498 stream->stream_tags);
11502 /* FIXME: what is in the chunk? */
11505 gint len = QT_UINT32 (stsd_data);
11507 /* seems to be always = 116 = 0x74 */
11513 gint len = QT_UINT32 (stsd_entry_data);
11516 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
11518 gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
11519 gst_caps_set_simple (entry->caps,
11520 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11521 gst_buffer_unref (buf);
11523 gst_caps_set_simple (entry->caps,
11524 "samplesize", G_TYPE_INT, samplesize, NULL);
11529 GNode *alac, *wave = NULL;
11531 /* apparently, m4a has this atom appended directly in the stsd entry,
11532 * while mov has it in a wave atom */
11533 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
11535 /* alac now refers to stsd entry atom */
11536 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
11538 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
11540 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
11543 const guint8 *alac_data = alac->data;
11544 gint len = QT_UINT32 (alac->data);
11548 GST_DEBUG_OBJECT (qtdemux,
11549 "discarding alac atom with unexpected len %d", len);
11551 /* codec-data contains alac atom size and prefix,
11552 * ffmpeg likes it that way, not quite gst-ish though ...*/
11553 buf = gst_buffer_new_and_alloc (len);
11554 gst_buffer_fill (buf, 0, alac->data, len);
11555 gst_caps_set_simple (entry->caps,
11556 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11557 gst_buffer_unref (buf);
11559 entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
11560 entry->n_channels = QT_UINT8 (alac_data + 21);
11561 entry->rate = QT_UINT32 (alac_data + 32);
11564 gst_caps_set_simple (entry->caps,
11565 "samplesize", G_TYPE_INT, samplesize, NULL);
11570 /* The codingname of the sample entry is 'fLaC' */
11571 GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
11574 /* The 'dfLa' box is added to the sample entry to convey
11575 initializing information for the decoder. */
11576 const GNode *dfla =
11577 qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
11580 const guint32 len = QT_UINT32 (dfla->data);
11582 /* Must contain at least dfLa box header (12),
11583 * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
11585 GST_DEBUG_OBJECT (qtdemux,
11586 "discarding dfla atom with unexpected len %d", len);
11588 /* skip dfLa header to get the METADATA_BLOCKs */
11589 const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
11590 const guint32 metadata_blocks_len = len - 12;
11592 gchar *stream_marker = g_strdup ("fLaC");
11593 GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
11594 strlen (stream_marker));
11597 guint32 remainder = 0;
11598 guint32 block_size = 0;
11599 gboolean is_last = FALSE;
11601 GValue array = G_VALUE_INIT;
11602 GValue value = G_VALUE_INIT;
11604 g_value_init (&array, GST_TYPE_ARRAY);
11605 g_value_init (&value, GST_TYPE_BUFFER);
11607 gst_value_set_buffer (&value, block);
11608 gst_value_array_append_value (&array, &value);
11609 g_value_reset (&value);
11611 gst_buffer_unref (block);
11613 /* check there's at least one METADATA_BLOCK_HEADER's worth
11614 * of data, and we haven't already finished parsing */
11615 while (!is_last && ((index + 3) < metadata_blocks_len)) {
11616 remainder = metadata_blocks_len - index;
11618 /* add the METADATA_BLOCK_HEADER size to the signalled size */
11620 (metadata_blocks[index + 1] << 16) +
11621 (metadata_blocks[index + 2] << 8) +
11622 metadata_blocks[index + 3];
11624 /* be careful not to read off end of box */
11625 if (block_size > remainder) {
11629 is_last = metadata_blocks[index] >> 7;
11631 block = gst_buffer_new_and_alloc (block_size);
11633 gst_buffer_fill (block, 0, &metadata_blocks[index],
11636 gst_value_set_buffer (&value, block);
11637 gst_value_array_append_value (&array, &value);
11638 g_value_reset (&value);
11640 gst_buffer_unref (block);
11642 index += block_size;
11645 /* only append the metadata if we successfully read all of it */
11647 gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
11648 (stream)->caps, 0), "streamheader", &array);
11650 GST_WARNING_OBJECT (qtdemux,
11651 "discarding all METADATA_BLOCKs due to invalid "
11652 "block_size %d at idx %d, rem %d", block_size, index,
11656 g_value_unset (&value);
11657 g_value_unset (&array);
11659 /* The sample rate obtained from the stsd may not be accurate
11660 * since it cannot represent rates greater than 65535Hz, so
11661 * override that value with the sample rate from the
11662 * METADATA_BLOCK_STREAMINFO block */
11663 CUR_STREAM (stream)->rate =
11664 (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
11675 gint len = QT_UINT32 (stsd_entry_data);
11678 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
11681 gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
11683 /* If we have enough data, let's try to get the 'damr' atom. See
11684 * the 3GPP container spec (26.244) for more details. */
11685 if ((len - 0x34) > 8 &&
11686 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
11687 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11688 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
11691 gst_caps_set_simple (entry->caps,
11692 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11693 gst_buffer_unref (buf);
11699 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
11700 gint len = QT_UINT32 (stsd_entry_data);
11703 guint16 sound_version = QT_UINT16 (stsd_entry_data + 16);
11705 if (sound_version == 1) {
11706 guint16 channels = QT_UINT16 (stsd_entry_data + 24);
11707 guint32 time_scale = QT_UINT32 (stsd_entry_data + 30);
11708 guint8 codec_data[2];
11710 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
11712 gint sample_rate_index =
11713 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
11715 /* build AAC codec data */
11716 codec_data[0] = profile << 3;
11717 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
11718 codec_data[1] = (sample_rate_index & 0x01) << 7;
11719 codec_data[1] |= (channels & 0xF) << 3;
11721 buf = gst_buffer_new_and_alloc (2);
11722 gst_buffer_fill (buf, 0, codec_data, 2);
11723 gst_caps_set_simple (entry->caps,
11724 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11725 gst_buffer_unref (buf);
11731 /* Fully handled elsewhere */
11734 GST_INFO_OBJECT (qtdemux,
11735 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11739 GST_INFO_OBJECT (qtdemux,
11740 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11741 GST_FOURCC_ARGS (fourcc), entry->caps);
11743 } else if (stream->subtype == FOURCC_strm) {
11744 if (fourcc == FOURCC_rtsp) {
11745 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
11747 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
11748 GST_FOURCC_ARGS (fourcc));
11749 goto unknown_stream;
11751 entry->sampled = TRUE;
11752 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
11753 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
11754 || stream->subtype == FOURCC_clcp) {
11756 entry->sampled = TRUE;
11757 entry->sparse = TRUE;
11760 qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11763 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11764 GST_TAG_SUBTITLE_CODEC, codec, NULL);
11769 /* hunt for sort-of codec data */
11773 GNode *mp4s = NULL;
11774 GNode *esds = NULL;
11776 /* look for palette in a stsd->mp4s->esds sub-atom */
11777 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
11779 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
11780 if (esds == NULL) {
11782 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
11786 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11787 stream->stream_tags);
11791 GST_INFO_OBJECT (qtdemux,
11792 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11795 GST_INFO_OBJECT (qtdemux,
11796 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11797 GST_FOURCC_ARGS (fourcc), entry->caps);
11799 /* everything in 1 sample */
11800 entry->sampled = TRUE;
11803 qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11806 if (entry->caps == NULL)
11807 goto unknown_stream;
11810 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11811 GST_TAG_SUBTITLE_CODEC, codec, NULL);
11817 /* promote to sampled format */
11818 if (entry->fourcc == FOURCC_samr) {
11819 /* force mono 8000 Hz for AMR */
11820 entry->sampled = TRUE;
11821 entry->n_channels = 1;
11822 entry->rate = 8000;
11823 } else if (entry->fourcc == FOURCC_sawb) {
11824 /* force mono 16000 Hz for AMR-WB */
11825 entry->sampled = TRUE;
11826 entry->n_channels = 1;
11827 entry->rate = 16000;
11828 } else if (entry->fourcc == FOURCC_mp4a) {
11829 entry->sampled = TRUE;
11833 stsd_entry_data += len;
11834 remaining_stsd_len -= len;
11838 /* collect sample information */
11839 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
11840 goto samples_failed;
11842 if (qtdemux->fragmented) {
11845 /* need all moov samples as basis; probably not many if any at all */
11846 /* prevent moof parsing taking of at this time */
11847 offset = qtdemux->moof_offset;
11848 qtdemux->moof_offset = 0;
11849 if (stream->n_samples &&
11850 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
11851 qtdemux->moof_offset = offset;
11852 goto samples_failed;
11854 qtdemux->moof_offset = 0;
11855 /* movie duration more reliable in this case (e.g. mehd) */
11856 if (qtdemux->segment.duration &&
11857 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
11859 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
11862 /* configure segments */
11863 if (!qtdemux_parse_segments (qtdemux, stream, trak))
11864 goto segments_failed;
11866 /* add some language tag, if useful */
11867 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
11868 strcmp (stream->lang_id, "und")) {
11869 const gchar *lang_code;
11871 /* convert ISO 639-2 code to ISO 639-1 */
11872 lang_code = gst_tag_get_language_code (stream->lang_id);
11873 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11874 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
11877 /* Check for UDTA tags */
11878 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
11879 qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
11882 /* now we are ready to add the stream */
11883 if (!qtdemux->got_moov) {
11884 qtdemux->active_streams = g_list_append (qtdemux->active_streams, stream);
11885 qtdemux->n_streams++;
11886 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
11894 GST_INFO_OBJECT (qtdemux, "skip disabled track");
11896 gst_qtdemux_stream_free (stream);
11901 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
11902 (_("This file is corrupt and cannot be played.")), (NULL));
11904 gst_qtdemux_stream_free (stream);
11909 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
11911 gst_qtdemux_stream_free (stream);
11917 /* we posted an error already */
11918 /* free stbl sub-atoms */
11919 gst_qtdemux_stbl_free (stream);
11921 gst_qtdemux_stream_free (stream);
11926 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
11929 gst_qtdemux_stream_free (stream);
11934 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
11935 GST_FOURCC_ARGS (stream->subtype));
11937 gst_qtdemux_stream_free (stream);
11942 /* If we can estimate the overall bitrate, and don't have information about the
11943 * stream bitrate for exactly one stream, this guesses the stream bitrate as
11944 * the overall bitrate minus the sum of the bitrates of all other streams. This
11945 * should be useful for the common case where we have one audio and one video
11946 * stream and can estimate the bitrate of one, but not the other. */
11948 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
11950 QtDemuxStream *stream = NULL;
11951 gint64 size, sys_bitrate, sum_bitrate = 0;
11952 GstClockTime duration;
11956 if (qtdemux->fragmented)
11959 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
11961 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
11963 GST_DEBUG_OBJECT (qtdemux,
11964 "Size in bytes of the stream not known - bailing");
11968 /* Subtract the header size */
11969 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
11970 size, qtdemux->header_size);
11972 if (size < qtdemux->header_size)
11975 size = size - qtdemux->header_size;
11977 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
11978 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
11982 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
11983 QtDemuxStream *str = QTDEMUX_STREAM (iter->data);
11984 switch (str->subtype) {
11987 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
11988 CUR_STREAM (str)->caps);
11989 /* retrieve bitrate, prefer avg then max */
11991 if (str->stream_tags) {
11992 if (gst_tag_list_get_uint (str->stream_tags,
11993 GST_TAG_MAXIMUM_BITRATE, &bitrate))
11994 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
11995 if (gst_tag_list_get_uint (str->stream_tags,
11996 GST_TAG_NOMINAL_BITRATE, &bitrate))
11997 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
11998 if (gst_tag_list_get_uint (str->stream_tags,
11999 GST_TAG_BITRATE, &bitrate))
12000 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
12003 sum_bitrate += bitrate;
12006 GST_DEBUG_OBJECT (qtdemux,
12007 ">1 stream with unknown bitrate - bailing");
12014 /* For other subtypes, we assume no significant impact on bitrate */
12020 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
12024 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
12026 if (sys_bitrate < sum_bitrate) {
12027 /* This can happen, since sum_bitrate might be derived from maximum
12028 * bitrates and not average bitrates */
12029 GST_DEBUG_OBJECT (qtdemux,
12030 "System bitrate less than sum bitrate - bailing");
12034 bitrate = sys_bitrate - sum_bitrate;
12035 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
12036 ", Stream bitrate = %u", sys_bitrate, bitrate);
12038 if (!stream->stream_tags)
12039 stream->stream_tags = gst_tag_list_new_empty ();
12041 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
12043 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12044 GST_TAG_BITRATE, bitrate, NULL);
12047 static GstFlowReturn
12048 qtdemux_prepare_streams (GstQTDemux * qtdemux)
12050 GstFlowReturn ret = GST_FLOW_OK;
12051 GList *iter, *next;
12053 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
12055 for (iter = qtdemux->active_streams; ret == GST_FLOW_OK && iter; iter = next) {
12056 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
12057 guint32 sample_num = 0;
12061 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
12062 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
12064 if (qtdemux->fragmented) {
12065 /* need all moov samples first */
12066 GST_OBJECT_LOCK (qtdemux);
12067 while (stream->n_samples == 0)
12068 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
12070 GST_OBJECT_UNLOCK (qtdemux);
12072 /* discard any stray moof */
12073 qtdemux->moof_offset = 0;
12076 /* prepare braking */
12077 if (ret != GST_FLOW_ERROR)
12080 /* in pull mode, we should have parsed some sample info by now;
12081 * and quite some code will not handle no samples.
12082 * in push mode, we'll just have to deal with it */
12083 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
12084 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
12085 gst_qtdemux_remove_stream (qtdemux, stream);
12089 /* parse the initial sample for use in setting the frame rate cap */
12090 while (sample_num == 0 && sample_num < stream->n_samples) {
12091 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
12095 if (stream->n_samples > 0 && stream->stbl_index >= 0) {
12096 stream->first_duration = stream->samples[0].duration;
12097 GST_LOG_OBJECT (qtdemux, "track-id %u first duration %u",
12098 stream->track_id, stream->first_duration);
12105 static GstFlowReturn
12106 qtdemux_expose_streams (GstQTDemux * qtdemux)
12108 GSList *oldpads = NULL;
12110 GList *walk, *next;
12112 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
12114 for (walk = qtdemux->active_streams; walk; walk = next) {
12115 QtDemuxStream *stream = QTDEMUX_STREAM (walk->data);
12116 GstPad *oldpad = stream->pad;
12121 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
12122 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
12124 if ((stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl) &&
12125 stream->track_id == qtdemux->chapters_track_id) {
12126 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
12127 so that it doesn't look like a subtitle track */
12128 gst_qtdemux_remove_stream (qtdemux, stream);
12132 /* now we have all info and can expose */
12133 list = stream->stream_tags;
12134 stream->stream_tags = NULL;
12136 oldpads = g_slist_prepend (oldpads, oldpad);
12137 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
12138 return GST_FLOW_ERROR;
12141 gst_qtdemux_guess_bitrate (qtdemux);
12143 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
12145 for (iter = oldpads; iter; iter = g_slist_next (iter)) {
12146 GstPad *oldpad = iter->data;
12149 event = gst_event_new_eos ();
12150 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
12151 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
12153 gst_pad_push_event (oldpad, event);
12154 gst_pad_set_active (oldpad, FALSE);
12155 gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
12156 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, oldpad);
12157 gst_object_unref (oldpad);
12160 /* check if we should post a redirect in case there is a single trak
12161 * and it is a redirecting trak */
12162 if (qtdemux->n_streams == 1 &&
12163 QTDEMUX_FIRST_STREAM (qtdemux)->redirect_uri != NULL) {
12166 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
12167 "an external content");
12168 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
12169 gst_structure_new ("redirect",
12170 "new-location", G_TYPE_STRING,
12171 QTDEMUX_FIRST_STREAM (qtdemux)->redirect_uri, NULL));
12172 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
12173 qtdemux->posted_redirect = TRUE;
12176 for (walk = qtdemux->active_streams; walk; walk = g_list_next (walk)) {
12177 qtdemux_do_allocation (qtdemux, QTDEMUX_STREAM (walk->data));
12180 qtdemux->exposed = TRUE;
12181 return GST_FLOW_OK;
12184 /* check if major or compatible brand is 3GP */
12185 static inline gboolean
12186 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
12189 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
12191 } else if (qtdemux->comp_brands != NULL) {
12195 gboolean res = FALSE;
12197 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
12200 while (size >= 4) {
12201 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
12206 gst_buffer_unmap (qtdemux->comp_brands, &map);
12213 /* check if tag is a spec'ed 3GP tag keyword storing a string */
12214 static inline gboolean
12215 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
12217 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
12218 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
12219 || fourcc == FOURCC_albm;
12223 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
12224 const char *tag, const char *dummy, GNode * node)
12226 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12230 gdouble longitude, latitude, altitude;
12233 len = QT_UINT32 (node->data);
12240 /* TODO: language code skipped */
12242 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
12245 /* do not alarm in trivial case, but bail out otherwise */
12246 if (*(data + offset) != 0) {
12247 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
12251 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
12252 GST_TAG_GEO_LOCATION_NAME, name, NULL);
12253 offset += strlen (name);
12257 if (len < offset + 2 + 4 + 4 + 4)
12260 /* +1 +1 = skip null-terminator and location role byte */
12262 /* table in spec says unsigned, semantics say negative has meaning ... */
12263 longitude = QT_SFP32 (data + offset);
12266 latitude = QT_SFP32 (data + offset);
12269 altitude = QT_SFP32 (data + offset);
12271 /* one invalid means all are invalid */
12272 if (longitude >= -180.0 && longitude <= 180.0 &&
12273 latitude >= -90.0 && latitude <= 90.0) {
12274 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
12275 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
12276 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
12277 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
12280 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
12287 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
12294 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
12295 const char *tag, const char *dummy, GNode * node)
12301 len = QT_UINT32 (node->data);
12305 y = QT_UINT16 ((guint8 *) node->data + 12);
12307 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
12310 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
12312 date = g_date_new_dmy (1, 1, y);
12313 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
12314 g_date_free (date);
12318 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
12319 const char *tag, const char *dummy, GNode * node)
12322 char *tag_str = NULL;
12327 len = QT_UINT32 (node->data);
12332 entity = (guint8 *) node->data + offset;
12333 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
12334 GST_DEBUG_OBJECT (qtdemux,
12335 "classification info: %c%c%c%c invalid classification entity",
12336 entity[0], entity[1], entity[2], entity[3]);
12341 table = QT_UINT16 ((guint8 *) node->data + offset);
12343 /* Language code skipped */
12347 /* Tag format: "XXXX://Y[YYYY]/classification info string"
12348 * XXXX: classification entity, fixed length 4 chars.
12349 * Y[YYYY]: classification table, max 5 chars.
12351 tag_str = g_strdup_printf ("----://%u/%s",
12352 table, (char *) node->data + offset);
12354 /* memcpy To be sure we're preserving byte order */
12355 memcpy (tag_str, entity, 4);
12356 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
12358 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
12367 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
12373 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
12374 const char *tag, const char *dummy, GNode * node)
12376 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12382 gboolean ret = TRUE;
12383 const gchar *charset = NULL;
12385 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12387 len = QT_UINT32 (data->data);
12388 type = QT_UINT32 ((guint8 *) data->data + 8);
12389 if (type == 0x00000001 && len > 16) {
12390 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
12393 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
12394 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
12397 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
12401 len = QT_UINT32 (node->data);
12402 type = QT_UINT32 ((guint8 *) node->data + 4);
12403 if ((type >> 24) == 0xa9 && len > 8 + 4) {
12407 /* Type starts with the (C) symbol, so the next data is a list
12408 * of (string size(16), language code(16), string) */
12410 str_len = QT_UINT16 ((guint8 *) node->data + 8);
12411 lang_code = QT_UINT16 ((guint8 *) node->data + 10);
12413 /* the string + fourcc + size + 2 16bit fields,
12414 * means that there are more tags in this atom */
12415 if (len > str_len + 8 + 4) {
12416 /* TODO how to represent the same tag in different languages? */
12417 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
12418 "text alternatives, reading only first one");
12422 len = MIN (len, str_len + 8 + 4); /* remove trailing strings that we don't use */
12423 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
12425 if (lang_code < 0x800) { /* MAC encoded string */
12428 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
12429 QT_FOURCC ((guint8 *) node->data + 4))) {
12430 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
12432 /* we go for 3GP style encoding if major brands claims so,
12433 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
12434 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
12435 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
12436 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
12438 /* 16-bit Language code is ignored here as well */
12439 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
12446 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
12447 ret = FALSE; /* may have to fallback */
12450 GError *err = NULL;
12452 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
12453 charset, NULL, NULL, &err);
12455 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
12456 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
12458 g_error_free (err);
12461 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
12462 len - offset, env_vars);
12465 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
12466 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
12470 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
12477 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
12478 const char *tag, const char *dummy, GNode * node)
12480 qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
12484 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
12485 const char *tag, const char *dummy, GNode * node)
12487 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12489 char *s, *t, *k = NULL;
12494 /* first try normal string tag if major brand not 3GP */
12495 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
12496 if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
12497 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
12498 * let's try it 3gpp way after minor safety check */
12500 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
12506 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
12510 len = QT_UINT32 (data);
12514 count = QT_UINT8 (data + 14);
12516 for (; count; count--) {
12519 if (offset + 1 > len)
12521 slen = QT_UINT8 (data + offset);
12523 if (offset + slen > len)
12525 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
12528 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
12530 t = g_strjoin (",", k, s, NULL);
12538 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
12545 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
12546 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
12555 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
12561 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
12562 const char *tag1, const char *tag2, GNode * node)
12569 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12571 len = QT_UINT32 (data->data);
12572 type = QT_UINT32 ((guint8 *) data->data + 8);
12573 if (type == 0x00000000 && len >= 22) {
12574 n1 = QT_UINT16 ((guint8 *) data->data + 18);
12575 n2 = QT_UINT16 ((guint8 *) data->data + 20);
12577 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
12578 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
12581 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
12582 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
12589 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
12590 const char *tag1, const char *dummy, GNode * node)
12597 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12599 len = QT_UINT32 (data->data);
12600 type = QT_UINT32 ((guint8 *) data->data + 8);
12601 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
12602 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
12603 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
12604 n1 = QT_UINT16 ((guint8 *) data->data + 16);
12606 /* do not add bpm=0 */
12607 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
12608 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
12616 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
12617 const char *tag1, const char *dummy, GNode * node)
12624 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12626 len = QT_UINT32 (data->data);
12627 type = QT_UINT32 ((guint8 *) data->data + 8);
12628 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
12629 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
12630 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
12631 num = QT_UINT32 ((guint8 *) data->data + 16);
12633 /* do not add num=0 */
12634 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
12635 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
12642 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
12643 const char *tag1, const char *dummy, GNode * node)
12650 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12652 len = QT_UINT32 (data->data);
12653 type = QT_UINT32 ((guint8 *) data->data + 8);
12654 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
12655 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
12656 GstTagImageType image_type;
12658 if (gst_tag_list_get_tag_size (taglist, GST_TAG_IMAGE) == 0)
12659 image_type = GST_TAG_IMAGE_TYPE_FRONT_COVER;
12661 image_type = GST_TAG_IMAGE_TYPE_NONE;
12664 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
12665 len - 16, image_type))) {
12666 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
12667 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
12668 gst_sample_unref (sample);
12675 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
12676 const char *tag, const char *dummy, GNode * node)
12679 GstDateTime *datetime = NULL;
12684 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12686 len = QT_UINT32 (data->data);
12687 type = QT_UINT32 ((guint8 *) data->data + 8);
12688 if (type == 0x00000001 && len > 16) {
12689 guint y, m = 1, d = 1;
12692 s = g_strndup ((char *) data->data + 16, len - 16);
12693 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
12694 datetime = gst_date_time_new_from_iso8601_string (s);
12695 if (datetime != NULL) {
12696 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, GST_TAG_DATE_TIME,
12698 gst_date_time_unref (datetime);
12701 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
12702 if (ret >= 1 && y > 1500 && y < 3000) {
12705 date = g_date_new_dmy (d, m, y);
12706 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
12707 g_date_free (date);
12709 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
12717 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
12718 const char *tag, const char *dummy, GNode * node)
12722 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12724 /* re-route to normal string tag if major brand says so
12725 * or no data atom and compatible brand suggests so */
12726 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
12727 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
12728 qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
12733 guint len, type, n;
12735 len = QT_UINT32 (data->data);
12736 type = QT_UINT32 ((guint8 *) data->data + 8);
12737 if (type == 0x00000000 && len >= 18) {
12738 n = QT_UINT16 ((guint8 *) data->data + 16);
12740 const gchar *genre;
12742 genre = gst_tag_id3_genre_get (n - 1);
12743 if (genre != NULL) {
12744 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
12745 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
12753 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
12754 const gchar * tag, guint8 * data, guint32 datasize)
12759 /* make a copy to have \0 at the end */
12760 datacopy = g_strndup ((gchar *) data, datasize);
12762 /* convert the str to double */
12763 if (sscanf (datacopy, "%lf", &value) == 1) {
12764 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
12765 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
12767 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
12775 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
12776 const char *tag, const char *tag_bis, GNode * node)
12785 const gchar *meanstr;
12786 const gchar *namestr;
12788 /* checking the whole ---- atom size for consistency */
12789 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
12790 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
12794 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
12796 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
12800 meansize = QT_UINT32 (mean->data);
12801 if (meansize <= 12) {
12802 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
12805 meanstr = ((gchar *) mean->data) + 12;
12808 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
12810 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
12814 namesize = QT_UINT32 (name->data);
12815 if (namesize <= 12) {
12816 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
12819 namestr = ((gchar *) name->data) + 12;
12827 * uint24 - data type
12831 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12833 GST_WARNING_OBJECT (demux, "No data atom in this tag");
12836 datasize = QT_UINT32 (data->data);
12837 if (datasize <= 16) {
12838 GST_WARNING_OBJECT (demux, "Data atom too small");
12841 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
12843 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
12844 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
12845 static const struct
12847 const gchar name[28];
12848 const gchar tag[28];
12851 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
12852 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
12853 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
12854 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
12855 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
12856 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
12857 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
12858 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
12862 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
12863 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
12864 switch (gst_tag_get_type (tags[i].tag)) {
12865 case G_TYPE_DOUBLE:
12866 qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
12867 ((guint8 *) data->data) + 16, datasize - 16);
12869 case G_TYPE_STRING:
12870 qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
12879 if (i == G_N_ELEMENTS (tags))
12889 #ifndef GST_DISABLE_GST_DEBUG
12891 gchar *namestr_dbg;
12892 gchar *meanstr_dbg;
12894 meanstr_dbg = g_strndup (meanstr, meansize);
12895 namestr_dbg = g_strndup (namestr, namesize);
12897 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
12898 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
12900 g_free (namestr_dbg);
12901 g_free (meanstr_dbg);
12908 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
12909 const char *tag_bis, GNode * node)
12914 GstTagList *id32_taglist = NULL;
12916 GST_LOG_OBJECT (demux, "parsing ID32");
12919 len = GST_READ_UINT32_BE (data);
12921 /* need at least full box and language tag */
12925 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
12926 gst_buffer_fill (buf, 0, data + 14, len - 14);
12928 id32_taglist = gst_tag_list_from_id3v2_tag (buf);
12929 if (id32_taglist) {
12930 GST_LOG_OBJECT (demux, "parsing ok");
12931 gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
12932 gst_tag_list_unref (id32_taglist);
12934 GST_LOG_OBJECT (demux, "parsing failed");
12937 gst_buffer_unref (buf);
12940 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
12941 const char *tag, const char *tag_bis, GNode * node);
12944 FOURCC_pcst -> if media is a podcast -> bool
12945 FOURCC_cpil -> if media is part of a compilation -> bool
12946 FOURCC_pgap -> if media is part of a gapless context -> bool
12947 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
12950 static const struct
12953 const gchar *gst_tag;
12954 const gchar *gst_tag_bis;
12955 const GstQTDemuxAddTagFunc func;
12958 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
12959 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
12960 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
12961 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
12962 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
12963 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
12964 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
12965 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
12966 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
12967 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
12968 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
12969 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
12970 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
12971 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12972 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12973 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12974 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
12975 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
12976 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
12977 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
12978 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
12979 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
12980 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
12981 qtdemux_tag_add_num}, {
12982 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
12983 qtdemux_tag_add_num}, {
12984 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
12985 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
12986 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
12987 FOURCC_covr, GST_TAG_IMAGE, NULL, qtdemux_tag_add_covr}, {
12988 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
12989 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
12990 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
12991 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
12992 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
12993 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
12994 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
12995 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
12996 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
12997 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
12998 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
12999 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
13000 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
13001 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
13002 qtdemux_tag_add_classification}, {
13003 FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
13004 FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
13005 FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
13007 /* This is a special case, some tags are stored in this
13008 * 'reverse dns naming', according to:
13009 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
13012 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
13013 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
13014 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
13017 struct _GstQtDemuxTagList
13020 GstTagList *taglist;
13022 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
13025 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
13031 const gchar *style;
13036 GstQTDemux *demux = qtdemuxtaglist->demux;
13037 GstTagList *taglist = qtdemuxtaglist->taglist;
13040 len = QT_UINT32 (data);
13041 buf = gst_buffer_new_and_alloc (len);
13042 gst_buffer_fill (buf, 0, data, len);
13044 /* heuristic to determine style of tag */
13045 if (QT_FOURCC (data + 4) == FOURCC_____ ||
13046 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
13048 else if (demux->major_brand == FOURCC_qt__)
13049 style = "quicktime";
13050 /* fall back to assuming iso/3gp tag style */
13054 /* santize the name for the caps. */
13055 for (i = 0; i < 4; i++) {
13056 guint8 d = data[4 + i];
13057 if (g_ascii_isalnum (d))
13058 ndata[i] = g_ascii_tolower (d);
13063 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
13064 ndata[0], ndata[1], ndata[2], ndata[3]);
13065 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
13067 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
13068 sample = gst_sample_new (buf, NULL, NULL, s);
13069 gst_buffer_unref (buf);
13070 g_free (media_type);
13072 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
13075 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
13076 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
13078 gst_sample_unref (sample);
13082 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
13089 GstQtDemuxTagList demuxtaglist;
13091 demuxtaglist.demux = qtdemux;
13092 demuxtaglist.taglist = taglist;
13094 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
13095 if (meta != NULL) {
13096 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
13097 if (ilst == NULL) {
13098 GST_LOG_OBJECT (qtdemux, "no ilst");
13103 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
13107 while (i < G_N_ELEMENTS (add_funcs)) {
13108 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
13112 len = QT_UINT32 (node->data);
13114 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
13115 GST_FOURCC_ARGS (add_funcs[i].fourcc));
13117 add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
13118 add_funcs[i].gst_tag_bis, node);
13120 g_node_destroy (node);
13126 /* parsed nodes have been removed, pass along remainder as blob */
13127 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
13128 (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
13130 /* parse up XMP_ node if existing */
13131 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
13132 if (xmp_ != NULL) {
13134 GstTagList *xmptaglist;
13136 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
13137 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
13138 xmptaglist = gst_tag_list_from_xmp_buffer (buf);
13139 gst_buffer_unref (buf);
13141 qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
13143 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
13149 GstStructure *structure; /* helper for sort function */
13151 guint min_req_bitrate;
13152 guint min_req_qt_version;
13156 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
13158 GstQtReference *ref_a = (GstQtReference *) a;
13159 GstQtReference *ref_b = (GstQtReference *) b;
13161 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
13162 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
13164 /* known bitrates go before unknown; higher bitrates go first */
13165 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
13168 /* sort the redirects and post a message for the application.
13171 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
13173 GstQtReference *best;
13176 GValue list_val = { 0, };
13179 g_assert (references != NULL);
13181 references = g_list_sort (references, qtdemux_redirects_sort_func);
13183 best = (GstQtReference *) references->data;
13185 g_value_init (&list_val, GST_TYPE_LIST);
13187 for (l = references; l != NULL; l = l->next) {
13188 GstQtReference *ref = (GstQtReference *) l->data;
13189 GValue struct_val = { 0, };
13191 ref->structure = gst_structure_new ("redirect",
13192 "new-location", G_TYPE_STRING, ref->location, NULL);
13194 if (ref->min_req_bitrate > 0) {
13195 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
13196 ref->min_req_bitrate, NULL);
13199 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
13200 g_value_set_boxed (&struct_val, ref->structure);
13201 gst_value_list_append_value (&list_val, &struct_val);
13202 g_value_unset (&struct_val);
13203 /* don't free anything here yet, since we need best->structure below */
13206 g_assert (best != NULL);
13207 s = gst_structure_copy (best->structure);
13209 if (g_list_length (references) > 1) {
13210 gst_structure_set_value (s, "locations", &list_val);
13213 g_value_unset (&list_val);
13215 for (l = references; l != NULL; l = l->next) {
13216 GstQtReference *ref = (GstQtReference *) l->data;
13218 gst_structure_free (ref->structure);
13219 g_free (ref->location);
13222 g_list_free (references);
13224 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
13225 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
13226 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
13227 qtdemux->posted_redirect = TRUE;
13230 /* look for redirect nodes, collect all redirect information and
13234 qtdemux_parse_redirects (GstQTDemux * qtdemux)
13236 GNode *rmra, *rmda, *rdrf;
13238 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
13240 GList *redirects = NULL;
13242 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
13244 GstQtReference ref = { NULL, NULL, 0, 0 };
13245 GNode *rmdr, *rmvc;
13247 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
13248 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
13249 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
13250 ref.min_req_bitrate);
13253 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
13254 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
13255 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
13257 #ifndef GST_DISABLE_GST_DEBUG
13258 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
13260 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
13262 GST_LOG_OBJECT (qtdemux,
13263 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
13264 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
13265 bitmask, check_type);
13266 if (package == FOURCC_qtim && check_type == 0) {
13267 ref.min_req_qt_version = version;
13271 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
13277 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
13278 if (ref_len > 20) {
13279 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
13280 ref_data = (guint8 *) rdrf->data + 20;
13281 if (ref_type == FOURCC_alis) {
13282 guint record_len, record_version, fn_len;
13284 if (ref_len > 70) {
13285 /* MacOSX alias record, google for alias-layout.txt */
13286 record_len = QT_UINT16 (ref_data + 4);
13287 record_version = QT_UINT16 (ref_data + 4 + 2);
13288 fn_len = QT_UINT8 (ref_data + 50);
13289 if (record_len > 50 && record_version == 2 && fn_len > 0) {
13290 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
13293 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
13296 } else if (ref_type == FOURCC_url_) {
13297 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
13299 GST_DEBUG_OBJECT (qtdemux,
13300 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
13301 GST_FOURCC_ARGS (ref_type));
13303 if (ref.location != NULL) {
13304 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
13306 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
13308 GST_WARNING_OBJECT (qtdemux,
13309 "Failed to extract redirect location from rdrf atom");
13312 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
13316 /* look for others */
13317 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
13320 if (redirects != NULL) {
13321 qtdemux_process_redirects (qtdemux, redirects);
13327 static GstTagList *
13328 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
13332 if (tags == NULL) {
13333 tags = gst_tag_list_new_empty ();
13334 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
13337 if (qtdemux->major_brand == FOURCC_mjp2)
13338 fmt = "Motion JPEG 2000";
13339 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
13341 else if (qtdemux->major_brand == FOURCC_qt__)
13343 else if (qtdemux->fragmented)
13346 fmt = "ISO MP4/M4A";
13348 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
13349 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
13351 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
13357 /* we have read the complete moov node now.
13358 * This function parses all of the relevant info, creates the traks and
13359 * prepares all data structures for playback
13362 qtdemux_parse_tree (GstQTDemux * qtdemux)
13368 GstClockTime duration;
13370 guint64 creation_time;
13371 GstDateTime *datetime = NULL;
13374 /* make sure we have a usable taglist */
13375 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13377 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
13378 if (mvhd == NULL) {
13379 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
13380 return qtdemux_parse_redirects (qtdemux);
13383 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
13384 if (version == 1) {
13385 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
13386 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
13387 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
13388 } else if (version == 0) {
13389 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
13390 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
13391 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
13393 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
13397 /* Moving qt creation time (secs since 1904) to unix time */
13398 if (creation_time != 0) {
13399 /* Try to use epoch first as it should be faster and more commonly found */
13400 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
13403 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
13404 /* some data cleansing sanity */
13405 g_get_current_time (&now);
13406 if (now.tv_sec + 24 * 3600 < creation_time) {
13407 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
13409 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
13412 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
13413 GDateTime *dt, *dt_local;
13415 dt = g_date_time_add_seconds (base_dt, creation_time);
13416 dt_local = g_date_time_to_local (dt);
13417 datetime = gst_date_time_new_from_g_date_time (dt_local);
13419 g_date_time_unref (base_dt);
13420 g_date_time_unref (dt);
13424 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
13425 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
13427 gst_date_time_unref (datetime);
13430 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
13431 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
13433 /* check for fragmented file and get some (default) data */
13434 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
13437 GstByteReader mehd_data;
13439 /* let track parsing or anyone know weird stuff might happen ... */
13440 qtdemux->fragmented = TRUE;
13442 /* compensate for total duration */
13443 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
13445 qtdemux_parse_mehd (qtdemux, &mehd_data);
13448 /* set duration in the segment info */
13449 gst_qtdemux_get_duration (qtdemux, &duration);
13451 qtdemux->segment.duration = duration;
13452 /* also do not exceed duration; stop is set that way post seek anyway,
13453 * and segment activation falls back to duration,
13454 * whereas loop only checks stop, so let's align this here as well */
13455 qtdemux->segment.stop = duration;
13458 /* parse all traks */
13459 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
13461 qtdemux_parse_trak (qtdemux, trak);
13462 /* iterate all siblings */
13463 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
13466 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13469 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
13471 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13473 GST_LOG_OBJECT (qtdemux, "No udta node found.");
13476 /* maybe also some tags in meta box */
13477 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
13479 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
13480 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13482 GST_LOG_OBJECT (qtdemux, "No meta node found.");
13485 /* parse any protection system info */
13486 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
13488 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
13489 qtdemux_parse_pssh (qtdemux, pssh);
13490 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
13493 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
13498 /* taken from ffmpeg */
13500 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
13512 len = (len << 7) | (c & 0x7f);
13521 parse_xiph_stream_headers (GstQTDemux * qtdemux, gpointer codec_data,
13522 gsize codec_data_size)
13524 GList *list = NULL;
13525 guint8 *p = codec_data;
13526 gint i, offset, num_packets;
13527 guint *length, last;
13529 GST_MEMDUMP_OBJECT (qtdemux, "xiph codec data", codec_data, codec_data_size);
13531 if (codec_data == NULL || codec_data_size == 0)
13534 /* start of the stream and vorbis audio or theora video, need to
13535 * send the codec_priv data as first three packets */
13536 num_packets = p[0] + 1;
13537 GST_DEBUG_OBJECT (qtdemux,
13538 "%u stream headers, total length=%" G_GSIZE_FORMAT " bytes",
13539 (guint) num_packets, codec_data_size);
13541 /* Let's put some limits, Don't think there even is a xiph codec
13542 * with more than 3-4 headers */
13543 if (G_UNLIKELY (num_packets > 16)) {
13544 GST_WARNING_OBJECT (qtdemux,
13545 "Unlikely number of xiph headers, most likely not valid");
13549 length = g_alloca (num_packets * sizeof (guint));
13553 /* first packets, read length values */
13554 for (i = 0; i < num_packets - 1; i++) {
13556 while (offset < codec_data_size) {
13557 length[i] += p[offset];
13558 if (p[offset++] != 0xff)
13563 if (offset + last > codec_data_size)
13566 /* last packet is the remaining size */
13567 length[i] = codec_data_size - offset - last;
13569 for (i = 0; i < num_packets; i++) {
13572 GST_DEBUG_OBJECT (qtdemux, "buffer %d: %u bytes", i, (guint) length[i]);
13574 if (offset + length[i] > codec_data_size)
13577 hdr = gst_buffer_new_wrapped (g_memdup (p + offset, length[i]), length[i]);
13578 list = g_list_append (list, hdr);
13580 offset += length[i];
13589 g_list_free_full (list, (GDestroyNotify) gst_buffer_unref);
13595 /* this can change the codec originally present in @list */
13597 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
13598 QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
13600 int len = QT_UINT32 (esds->data);
13601 guint8 *ptr = esds->data;
13602 guint8 *end = ptr + len;
13604 guint8 *data_ptr = NULL;
13606 guint8 object_type_id = 0;
13607 guint8 stream_type = 0;
13608 const char *codec_name = NULL;
13609 GstCaps *caps = NULL;
13611 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
13613 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
13615 while (ptr + 1 < end) {
13616 tag = QT_UINT8 (ptr);
13617 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
13619 len = read_descr_size (ptr, end, &ptr);
13620 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
13622 /* Check the stated amount of data is available for reading */
13623 if (len < 0 || ptr + len > end)
13627 case ES_DESCRIPTOR_TAG:
13628 GST_DEBUG_OBJECT (qtdemux, "ID 0x%04x", QT_UINT16 (ptr));
13629 GST_DEBUG_OBJECT (qtdemux, "priority 0x%04x", QT_UINT8 (ptr + 2));
13632 case DECODER_CONFIG_DESC_TAG:{
13633 guint max_bitrate, avg_bitrate;
13635 object_type_id = QT_UINT8 (ptr);
13636 stream_type = QT_UINT8 (ptr + 1) >> 2;
13637 max_bitrate = QT_UINT32 (ptr + 5);
13638 avg_bitrate = QT_UINT32 (ptr + 9);
13639 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
13640 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", stream_type);
13641 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
13642 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
13643 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
13644 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
13645 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
13646 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
13648 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
13649 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
13650 avg_bitrate, NULL);
13655 case DECODER_SPECIFIC_INFO_TAG:
13656 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
13657 if (object_type_id == 0xe0 && len == 0x40) {
13663 GST_DEBUG_OBJECT (qtdemux,
13664 "Have VOBSUB palette. Creating palette event");
13665 /* move to decConfigDescr data and read palette */
13667 for (i = 0; i < 16; i++) {
13668 clut[i] = QT_UINT32 (data);
13672 s = gst_structure_new ("application/x-gst-dvd", "event",
13673 G_TYPE_STRING, "dvd-spu-clut-change",
13674 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
13675 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
13676 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
13677 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
13678 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
13679 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
13680 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
13681 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
13684 /* store event and trigger custom processing */
13685 stream->pending_event =
13686 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
13688 /* Generic codec_data handler puts it on the caps */
13695 case SL_CONFIG_DESC_TAG:
13696 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
13700 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
13702 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
13708 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
13709 * in use, and should also be used to override some other parameters for some
13711 switch (object_type_id) {
13712 case 0x20: /* MPEG-4 */
13713 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
13714 * profile_and_level_indication */
13715 if (data_ptr != NULL && data_len >= 5 &&
13716 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
13717 gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
13718 data_ptr + 4, data_len - 4);
13720 break; /* Nothing special needed here */
13721 case 0x21: /* H.264 */
13722 codec_name = "H.264 / AVC";
13723 caps = gst_caps_new_simple ("video/x-h264",
13724 "stream-format", G_TYPE_STRING, "avc",
13725 "alignment", G_TYPE_STRING, "au", NULL);
13727 case 0x40: /* AAC (any) */
13728 case 0x66: /* AAC Main */
13729 case 0x67: /* AAC LC */
13730 case 0x68: /* AAC SSR */
13731 /* Override channels and rate based on the codec_data, as it's often
13733 /* Only do so for basic setup without HE-AAC extension */
13734 if (data_ptr && data_len == 2) {
13735 guint channels, rate;
13737 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
13739 entry->n_channels = channels;
13741 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
13743 entry->rate = rate;
13746 /* Set level and profile if possible */
13747 if (data_ptr != NULL && data_len >= 2) {
13748 gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
13749 data_ptr, data_len);
13751 const gchar *profile_str = NULL;
13754 guint8 *codec_data;
13755 gint rate_idx, profile;
13757 /* No codec_data, let's invent something.
13758 * FIXME: This is wrong for SBR! */
13760 GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
13762 buffer = gst_buffer_new_and_alloc (2);
13763 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
13764 codec_data = map.data;
13767 gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
13770 switch (object_type_id) {
13772 profile_str = "main";
13776 profile_str = "lc";
13780 profile_str = "ssr";
13788 codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
13790 ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
13792 gst_buffer_unmap (buffer, &map);
13793 gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
13794 GST_TYPE_BUFFER, buffer, NULL);
13795 gst_buffer_unref (buffer);
13798 gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
13799 G_TYPE_STRING, profile_str, NULL);
13803 case 0x60: /* MPEG-2, various profiles */
13809 codec_name = "MPEG-2 video";
13810 caps = gst_caps_new_simple ("video/mpeg",
13811 "mpegversion", G_TYPE_INT, 2,
13812 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13814 case 0x69: /* MPEG-2 BC audio */
13815 case 0x6B: /* MPEG-1 audio */
13816 caps = gst_caps_new_simple ("audio/mpeg",
13817 "mpegversion", G_TYPE_INT, 1, NULL);
13818 codec_name = "MPEG-1 audio";
13820 case 0x6A: /* MPEG-1 */
13821 codec_name = "MPEG-1 video";
13822 caps = gst_caps_new_simple ("video/mpeg",
13823 "mpegversion", G_TYPE_INT, 1,
13824 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13826 case 0x6C: /* MJPEG */
13828 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13830 codec_name = "Motion-JPEG";
13832 case 0x6D: /* PNG */
13834 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
13836 codec_name = "PNG still images";
13838 case 0x6E: /* JPEG2000 */
13839 codec_name = "JPEG-2000";
13840 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
13842 case 0xA4: /* Dirac */
13843 codec_name = "Dirac";
13844 caps = gst_caps_new_empty_simple ("video/x-dirac");
13846 case 0xA5: /* AC3 */
13847 codec_name = "AC-3 audio";
13848 caps = gst_caps_new_simple ("audio/x-ac3",
13849 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13851 case 0xA9: /* AC3 */
13852 codec_name = "DTS audio";
13853 caps = gst_caps_new_simple ("audio/x-dts",
13854 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13857 if (stream_type == 0x05 && data_ptr) {
13859 parse_xiph_stream_headers (qtdemux, data_ptr, data_len);
13862 GValue arr_val = G_VALUE_INIT;
13863 GValue buf_val = G_VALUE_INIT;
13866 /* Let's assume it's vorbis if it's an audio stream of type 0xdd and we have codec data that extracts properly */
13867 codec_name = "Vorbis";
13868 caps = gst_caps_new_empty_simple ("audio/x-vorbis");
13869 g_value_init (&arr_val, GST_TYPE_ARRAY);
13870 g_value_init (&buf_val, GST_TYPE_BUFFER);
13871 for (tmp = headers; tmp; tmp = tmp->next) {
13872 g_value_set_boxed (&buf_val, (GstBuffer *) tmp->data);
13873 gst_value_array_append_value (&arr_val, &buf_val);
13875 s = gst_caps_get_structure (caps, 0);
13876 gst_structure_take_value (s, "streamheader", &arr_val);
13877 g_value_unset (&buf_val);
13878 g_list_free (headers);
13885 case 0xE1: /* QCELP */
13886 /* QCELP, the codec_data is a riff tag (little endian) with
13887 * 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). */
13888 caps = gst_caps_new_empty_simple ("audio/qcelp");
13889 codec_name = "QCELP";
13895 /* If we have a replacement caps, then change our caps for this stream */
13897 gst_caps_unref (entry->caps);
13898 entry->caps = caps;
13901 if (codec_name && list)
13902 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
13903 GST_TAG_AUDIO_CODEC, codec_name, NULL);
13905 /* Add the codec_data attribute to caps, if we have it */
13909 buffer = gst_buffer_new_and_alloc (data_len);
13910 gst_buffer_fill (buffer, 0, data_ptr, data_len);
13912 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
13913 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
13915 gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
13917 gst_buffer_unref (buffer);
13922 static inline GstCaps *
13923 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
13927 char *s, fourstr[5];
13929 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13930 for (i = 0; i < 4; i++) {
13931 if (!g_ascii_isalnum (fourstr[i]))
13934 s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
13935 caps = gst_caps_new_empty_simple (s);
13940 #define _codec(name) \
13942 if (codec_name) { \
13943 *codec_name = g_strdup (name); \
13948 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13949 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
13950 const guint8 * stsd_entry_data, gchar ** codec_name)
13952 GstCaps *caps = NULL;
13953 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
13957 _codec ("PNG still images");
13958 caps = gst_caps_new_empty_simple ("image/png");
13961 _codec ("JPEG still images");
13963 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13966 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
13967 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
13968 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
13969 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
13970 _codec ("Motion-JPEG");
13972 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13975 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
13976 _codec ("Motion-JPEG format B");
13977 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
13980 _codec ("JPEG-2000");
13981 /* override to what it should be according to spec, avoid palette_data */
13982 entry->bits_per_sample = 24;
13983 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
13986 _codec ("Sorensen video v.3");
13987 caps = gst_caps_new_simple ("video/x-svq",
13988 "svqversion", G_TYPE_INT, 3, NULL);
13990 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
13991 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
13992 _codec ("Sorensen video v.1");
13993 caps = gst_caps_new_simple ("video/x-svq",
13994 "svqversion", G_TYPE_INT, 1, NULL);
13996 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
13997 caps = gst_caps_new_empty_simple ("video/x-raw");
13998 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
13999 _codec ("Windows Raw RGB");
14000 stream->alignment = 32;
14006 bps = QT_UINT16 (stsd_entry_data + 82);
14009 format = GST_VIDEO_FORMAT_RGB15;
14012 format = GST_VIDEO_FORMAT_RGB16;
14015 format = GST_VIDEO_FORMAT_RGB;
14018 format = GST_VIDEO_FORMAT_ARGB;
14026 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
14027 format = GST_VIDEO_FORMAT_I420;
14029 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
14030 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
14031 format = GST_VIDEO_FORMAT_I420;
14034 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
14035 format = GST_VIDEO_FORMAT_UYVY;
14037 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
14038 format = GST_VIDEO_FORMAT_v308;
14040 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
14041 format = GST_VIDEO_FORMAT_v216;
14044 format = GST_VIDEO_FORMAT_v210;
14046 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
14047 format = GST_VIDEO_FORMAT_r210;
14049 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
14050 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
14051 format = GST_VIDEO_FORMAT_v410;
14054 /* Packed YUV 4:4:4:4 8 bit in 32 bits
14055 * but different order than AYUV
14056 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
14057 format = GST_VIDEO_FORMAT_v408;
14060 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
14061 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
14062 _codec ("MPEG-1 video");
14063 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14064 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14066 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
14067 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
14068 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
14069 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
14070 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
14071 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
14072 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
14073 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
14074 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
14075 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
14076 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
14077 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
14078 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
14079 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
14080 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
14081 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
14082 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
14083 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
14084 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
14085 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
14086 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
14087 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
14088 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
14089 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
14090 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
14091 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
14092 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
14093 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
14094 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
14095 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
14096 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
14097 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
14098 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
14099 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
14100 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
14101 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
14102 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14103 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14104 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
14105 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
14106 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
14107 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
14108 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
14109 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
14110 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
14111 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
14112 case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
14113 _codec ("MPEG-2 video");
14114 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
14115 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14117 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
14118 _codec ("GIF still images");
14119 caps = gst_caps_new_empty_simple ("image/gif");
14122 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
14124 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
14126 /* ffmpeg uses the height/width props, don't know why */
14127 caps = gst_caps_new_simple ("video/x-h263",
14128 "variant", G_TYPE_STRING, "itu", NULL);
14132 _codec ("MPEG-4 video");
14133 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14134 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14136 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
14137 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
14138 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
14139 caps = gst_caps_new_simple ("video/x-msmpeg",
14140 "msmpegversion", G_TYPE_INT, 43, NULL);
14142 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
14144 caps = gst_caps_new_simple ("video/x-divx",
14145 "divxversion", G_TYPE_INT, 3, NULL);
14147 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
14148 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
14150 caps = gst_caps_new_simple ("video/x-divx",
14151 "divxversion", G_TYPE_INT, 4, NULL);
14153 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
14155 caps = gst_caps_new_simple ("video/x-divx",
14156 "divxversion", G_TYPE_INT, 5, NULL);
14159 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
14161 caps = gst_caps_new_simple ("video/x-ffv",
14162 "ffvversion", G_TYPE_INT, 1, NULL);
14165 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
14166 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
14171 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
14172 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14173 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14177 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
14178 _codec ("Cinepak");
14179 caps = gst_caps_new_empty_simple ("video/x-cinepak");
14181 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
14182 _codec ("Apple QuickDraw");
14183 caps = gst_caps_new_empty_simple ("video/x-qdrw");
14185 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
14186 _codec ("Apple video");
14187 caps = gst_caps_new_empty_simple ("video/x-apple-video");
14191 _codec ("H.264 / AVC");
14192 caps = gst_caps_new_simple ("video/x-h264",
14193 "stream-format", G_TYPE_STRING, "avc",
14194 "alignment", G_TYPE_STRING, "au", NULL);
14197 _codec ("H.264 / AVC");
14198 caps = gst_caps_new_simple ("video/x-h264",
14199 "stream-format", G_TYPE_STRING, "avc3",
14200 "alignment", G_TYPE_STRING, "au", NULL);
14204 _codec ("H.265 / HEVC");
14205 caps = gst_caps_new_simple ("video/x-h265",
14206 "stream-format", G_TYPE_STRING, "hvc1",
14207 "alignment", G_TYPE_STRING, "au", NULL);
14210 _codec ("H.265 / HEVC");
14211 caps = gst_caps_new_simple ("video/x-h265",
14212 "stream-format", G_TYPE_STRING, "hev1",
14213 "alignment", G_TYPE_STRING, "au", NULL);
14216 _codec ("Run-length encoding");
14217 caps = gst_caps_new_simple ("video/x-rle",
14218 "layout", G_TYPE_STRING, "quicktime", NULL);
14221 _codec ("Run-length encoding");
14222 caps = gst_caps_new_simple ("video/x-rle",
14223 "layout", G_TYPE_STRING, "microsoft", NULL);
14225 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
14226 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
14227 _codec ("Indeo Video 3");
14228 caps = gst_caps_new_simple ("video/x-indeo",
14229 "indeoversion", G_TYPE_INT, 3, NULL);
14231 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
14232 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
14233 _codec ("Intel Video 4");
14234 caps = gst_caps_new_simple ("video/x-indeo",
14235 "indeoversion", G_TYPE_INT, 4, NULL);
14239 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
14240 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
14241 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
14242 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
14243 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
14244 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
14245 _codec ("DV Video");
14246 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
14247 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14249 case FOURCC_dv5n: /* DVCPRO50 NTSC */
14250 case FOURCC_dv5p: /* DVCPRO50 PAL */
14251 _codec ("DVCPro50 Video");
14252 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
14253 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14255 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
14256 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
14257 _codec ("DVCProHD Video");
14258 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
14259 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14261 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
14262 _codec ("Apple Graphics (SMC)");
14263 caps = gst_caps_new_empty_simple ("video/x-smc");
14265 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
14267 caps = gst_caps_new_empty_simple ("video/x-vp3");
14269 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
14270 _codec ("VP6 Flash");
14271 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
14275 caps = gst_caps_new_empty_simple ("video/x-theora");
14276 /* theora uses one byte of padding in the data stream because it does not
14277 * allow 0 sized packets while theora does */
14278 entry->padding = 1;
14282 caps = gst_caps_new_empty_simple ("video/x-dirac");
14284 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
14285 _codec ("TIFF still images");
14286 caps = gst_caps_new_empty_simple ("image/tiff");
14288 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
14289 _codec ("Apple Intermediate Codec");
14290 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
14292 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
14293 _codec ("AVID DNxHD");
14294 caps = gst_caps_from_string ("video/x-dnxhd");
14298 _codec ("On2 VP8");
14299 caps = gst_caps_from_string ("video/x-vp8");
14302 _codec ("Google VP9");
14303 caps = gst_caps_from_string ("video/x-vp9");
14306 _codec ("Apple ProRes LT");
14308 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
14312 _codec ("Apple ProRes HQ");
14314 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
14318 _codec ("Apple ProRes");
14320 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14324 _codec ("Apple ProRes Proxy");
14326 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14330 _codec ("Apple ProRes 4444");
14332 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14336 _codec ("Apple ProRes 4444 XQ");
14338 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14342 _codec ("GoPro CineForm");
14343 caps = gst_caps_from_string ("video/x-cineform");
14348 caps = gst_caps_new_simple ("video/x-wmv",
14349 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
14351 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
14354 caps = _get_unknown_codec_name ("video", fourcc);
14359 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
14362 gst_video_info_init (&info);
14363 gst_video_info_set_format (&info, format, entry->width, entry->height);
14365 caps = gst_video_info_to_caps (&info);
14366 *codec_name = gst_pb_utils_get_codec_description (caps);
14368 /* enable clipping for raw video streams */
14369 stream->need_clip = TRUE;
14370 stream->alignment = 32;
14377 round_up_pow2 (guint n)
14389 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14390 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
14391 int len, gchar ** codec_name)
14394 const GstStructure *s;
14397 GstAudioFormat format = 0;
14400 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14402 depth = entry->bytes_per_packet * 8;
14405 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
14407 /* 8-bit audio is unsigned */
14409 format = GST_AUDIO_FORMAT_U8;
14410 /* otherwise it's signed and big-endian just like 'twos' */
14412 endian = G_BIG_ENDIAN;
14419 endian = G_LITTLE_ENDIAN;
14422 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
14424 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
14428 caps = gst_caps_new_simple ("audio/x-raw",
14429 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14430 "layout", G_TYPE_STRING, "interleaved", NULL);
14431 stream->alignment = GST_ROUND_UP_8 (depth);
14432 stream->alignment = round_up_pow2 (stream->alignment);
14435 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
14436 _codec ("Raw 64-bit floating-point audio");
14437 caps = gst_caps_new_simple ("audio/x-raw",
14438 "format", G_TYPE_STRING, "F64BE",
14439 "layout", G_TYPE_STRING, "interleaved", NULL);
14440 stream->alignment = 8;
14442 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
14443 _codec ("Raw 32-bit floating-point audio");
14444 caps = gst_caps_new_simple ("audio/x-raw",
14445 "format", G_TYPE_STRING, "F32BE",
14446 "layout", G_TYPE_STRING, "interleaved", NULL);
14447 stream->alignment = 4;
14450 _codec ("Raw 24-bit PCM audio");
14451 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14453 caps = gst_caps_new_simple ("audio/x-raw",
14454 "format", G_TYPE_STRING, "S24BE",
14455 "layout", G_TYPE_STRING, "interleaved", NULL);
14456 stream->alignment = 4;
14458 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
14459 _codec ("Raw 32-bit PCM audio");
14460 caps = gst_caps_new_simple ("audio/x-raw",
14461 "format", G_TYPE_STRING, "S32BE",
14462 "layout", G_TYPE_STRING, "interleaved", NULL);
14463 stream->alignment = 4;
14465 case GST_MAKE_FOURCC ('s', '1', '6', 'l'):
14466 _codec ("Raw 16-bit PCM audio");
14467 caps = gst_caps_new_simple ("audio/x-raw",
14468 "format", G_TYPE_STRING, "S16LE",
14469 "layout", G_TYPE_STRING, "interleaved", NULL);
14470 stream->alignment = 2;
14473 _codec ("Mu-law audio");
14474 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
14477 _codec ("A-law audio");
14478 caps = gst_caps_new_empty_simple ("audio/x-alaw");
14482 _codec ("Microsoft ADPCM");
14483 /* Microsoft ADPCM-ACM code 2 */
14484 caps = gst_caps_new_simple ("audio/x-adpcm",
14485 "layout", G_TYPE_STRING, "microsoft", NULL);
14489 _codec ("DVI/IMA ADPCM");
14490 caps = gst_caps_new_simple ("audio/x-adpcm",
14491 "layout", G_TYPE_STRING, "dvi", NULL);
14495 _codec ("DVI/Intel IMA ADPCM");
14496 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
14497 caps = gst_caps_new_simple ("audio/x-adpcm",
14498 "layout", G_TYPE_STRING, "quicktime", NULL);
14502 /* MPEG layer 3, CBR only (pre QT4.1) */
14504 _codec ("MPEG-1 layer 3");
14505 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
14506 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
14507 "mpegversion", G_TYPE_INT, 1, NULL);
14509 case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
14510 _codec ("MPEG-1 layer 2");
14512 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
14513 "mpegversion", G_TYPE_INT, 1, NULL);
14516 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
14517 _codec ("EAC-3 audio");
14518 caps = gst_caps_new_simple ("audio/x-eac3",
14519 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14520 entry->sampled = TRUE;
14522 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
14524 _codec ("AC-3 audio");
14525 caps = gst_caps_new_simple ("audio/x-ac3",
14526 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14527 entry->sampled = TRUE;
14529 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
14530 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
14531 _codec ("DTS audio");
14532 caps = gst_caps_new_simple ("audio/x-dts",
14533 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14534 entry->sampled = TRUE;
14536 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
14537 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
14538 _codec ("DTS-HD audio");
14539 caps = gst_caps_new_simple ("audio/x-dts",
14540 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14541 entry->sampled = TRUE;
14545 caps = gst_caps_new_simple ("audio/x-mace",
14546 "maceversion", G_TYPE_INT, 3, NULL);
14550 caps = gst_caps_new_simple ("audio/x-mace",
14551 "maceversion", G_TYPE_INT, 6, NULL);
14553 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
14555 caps = gst_caps_new_empty_simple ("application/ogg");
14557 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
14558 _codec ("DV audio");
14559 caps = gst_caps_new_empty_simple ("audio/x-dv");
14562 _codec ("MPEG-4 AAC audio");
14563 caps = gst_caps_new_simple ("audio/mpeg",
14564 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
14565 "stream-format", G_TYPE_STRING, "raw", NULL);
14567 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
14568 _codec ("QDesign Music");
14569 caps = gst_caps_new_empty_simple ("audio/x-qdm");
14572 _codec ("QDesign Music v.2");
14573 /* FIXME: QDesign music version 2 (no constant) */
14574 if (FALSE && data) {
14575 caps = gst_caps_new_simple ("audio/x-qdm2",
14576 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
14577 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
14578 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
14580 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
14584 _codec ("GSM audio");
14585 caps = gst_caps_new_empty_simple ("audio/x-gsm");
14588 _codec ("AMR audio");
14589 caps = gst_caps_new_empty_simple ("audio/AMR");
14592 _codec ("AMR-WB audio");
14593 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
14596 _codec ("Quicktime IMA ADPCM");
14597 caps = gst_caps_new_simple ("audio/x-adpcm",
14598 "layout", G_TYPE_STRING, "quicktime", NULL);
14601 _codec ("Apple lossless audio");
14602 caps = gst_caps_new_empty_simple ("audio/x-alac");
14605 _codec ("Free Lossless Audio Codec");
14606 caps = gst_caps_new_simple ("audio/x-flac",
14607 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14609 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
14610 _codec ("QualComm PureVoice");
14611 caps = gst_caps_from_string ("audio/qcelp");
14616 caps = gst_caps_new_empty_simple ("audio/x-wma");
14620 caps = gst_caps_new_empty_simple ("audio/x-opus");
14627 GstAudioFormat format;
14630 FLAG_IS_FLOAT = 0x1,
14631 FLAG_IS_BIG_ENDIAN = 0x2,
14632 FLAG_IS_SIGNED = 0x4,
14633 FLAG_IS_PACKED = 0x8,
14634 FLAG_IS_ALIGNED_HIGH = 0x10,
14635 FLAG_IS_NON_INTERLEAVED = 0x20
14637 _codec ("Raw LPCM audio");
14639 if (data && len >= 36) {
14640 depth = QT_UINT32 (data + 24);
14641 flags = QT_UINT32 (data + 28);
14642 width = QT_UINT32 (data + 32) * 8 / entry->n_channels;
14644 if ((flags & FLAG_IS_FLOAT) == 0) {
14649 if ((flags & FLAG_IS_ALIGNED_HIGH))
14652 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
14653 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
14654 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
14655 caps = gst_caps_new_simple ("audio/x-raw",
14656 "format", G_TYPE_STRING,
14658 GST_AUDIO_FORMAT_UNKNOWN ? gst_audio_format_to_string (format) :
14659 "UNKNOWN", "layout", G_TYPE_STRING,
14660 (flags & FLAG_IS_NON_INTERLEAVED) ? "non-interleaved" :
14661 "interleaved", NULL);
14662 stream->alignment = GST_ROUND_UP_8 (depth);
14663 stream->alignment = round_up_pow2 (stream->alignment);
14668 if (flags & FLAG_IS_BIG_ENDIAN)
14669 format = GST_AUDIO_FORMAT_F64BE;
14671 format = GST_AUDIO_FORMAT_F64LE;
14673 if (flags & FLAG_IS_BIG_ENDIAN)
14674 format = GST_AUDIO_FORMAT_F32BE;
14676 format = GST_AUDIO_FORMAT_F32LE;
14678 caps = gst_caps_new_simple ("audio/x-raw",
14679 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14680 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
14681 "non-interleaved" : "interleaved", NULL);
14682 stream->alignment = width / 8;
14686 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
14690 caps = _get_unknown_codec_name ("audio", fourcc);
14696 GstCaps *templ_caps =
14697 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
14698 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
14699 gst_caps_unref (caps);
14700 gst_caps_unref (templ_caps);
14701 caps = intersection;
14704 /* enable clipping for raw audio streams */
14705 s = gst_caps_get_structure (caps, 0);
14706 name = gst_structure_get_name (s);
14707 if (g_str_has_prefix (name, "audio/x-raw")) {
14708 stream->need_clip = TRUE;
14709 stream->max_buffer_size = 4096 * entry->bytes_per_frame;
14710 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
14716 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14717 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14718 const guint8 * stsd_entry_data, gchar ** codec_name)
14722 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14726 _codec ("DVD subtitle");
14727 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
14728 stream->need_process = TRUE;
14731 _codec ("Quicktime timed text");
14734 _codec ("3GPP timed text");
14736 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
14738 /* actual text piece needs to be extracted */
14739 stream->need_process = TRUE;
14742 _codec ("XML subtitles");
14743 caps = gst_caps_new_empty_simple ("application/ttml+xml");
14746 _codec ("CEA 608 Closed Caption");
14748 gst_caps_new_simple ("closedcaption/x-cea-608", "format",
14749 G_TYPE_STRING, "cc_data", NULL);
14750 stream->need_process = TRUE;
14753 _codec ("CEA 708 Closed Caption");
14755 gst_caps_new_simple ("closedcaption/x-cea-708", "format",
14756 G_TYPE_STRING, "cdp", NULL);
14757 stream->need_process = TRUE;
14762 caps = _get_unknown_codec_name ("text", fourcc);
14770 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14771 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14772 const guint8 * stsd_entry_data, gchar ** codec_name)
14778 _codec ("MPEG 1 video");
14779 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14780 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14790 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
14791 const gchar * system_id)
14795 if (!qtdemux->protection_system_ids)
14796 qtdemux->protection_system_ids =
14797 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
14798 /* Check whether we already have an entry for this system ID. */
14799 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
14800 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
14801 if (g_ascii_strcasecmp (system_id, id) == 0) {
14805 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
14806 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,