2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) <2003> David A. Schleef <ds@schleef.org>
4 * Copyright (C) <2006> Wim Taymans <wim@fluendo.com>
5 * Copyright (C) <2007> Julien Moutte <julien@fluendo.com>
6 * Copyright (C) <2009> Tim-Philipp Müller <tim centricular net>
7 * Copyright (C) <2009> STEricsson <benjamin.gaignard@stericsson.com>
8 * Copyright (C) <2013> Sreerenj Balachandran <sreerenj.balachandran@intel.com>
9 * Copyright (C) <2013> Intel Corporation
10 * Copyright (C) <2014> Centricular Ltd
11 * Copyright (C) <2015> YouView TV Ltd.
12 * Copyright (C) <2016> British Broadcasting Corporation
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Library General Public
16 * License as published by the Free Software Foundation; either
17 * version 2 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Library General Public License for more details.
24 * You should have received a copy of the GNU Library General Public
25 * License along with this library; if not, write to the
26 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
27 * Boston, MA 02110-1301, USA.
31 * SECTION:element-qtdemux
33 * Demuxes a .mov file into raw or compressed audio and/or video streams.
35 * This element supports both push and pull-based scheduling, depending on the
36 * capabilities of the upstream elements.
39 * <title>Example launch line</title>
41 * gst-launch-1.0 filesrc location=test.mov ! qtdemux name=demux demux.audio_0 ! queue ! decodebin ! audioconvert ! audioresample ! autoaudiosink demux.video_0 ! queue ! decodebin ! videoconvert ! videoscale ! autovideosink
42 * ]| Play (parse and decode) a .mov file and try to output it to
43 * an automatically detected soundcard and videosink. If the MOV file contains
44 * compressed audio or video data, this will only work if you have the
45 * right decoder elements/plugins installed.
53 #include "gst/gst-i18n-plugin.h"
55 #include <glib/gprintf.h>
56 #include <gst/tag/tag.h>
57 #include <gst/audio/audio.h>
58 #include <gst/video/video.h>
60 #include "qtatomparser.h"
61 #include "qtdemux_types.h"
62 #include "qtdemux_dump.h"
64 #include "descriptors.h"
65 #include "qtdemux_lang.h"
67 #include "qtpalette.h"
69 #include "gst/riff/riff-media.h"
70 #include "gst/riff/riff-read.h"
72 #include <gst/pbutils/pbutils.h>
79 #include <gst/math-compat.h>
85 /* max. size considered 'sane' for non-mdat atoms */
86 #define QTDEMUX_MAX_ATOM_SIZE (25*1024*1024)
88 /* if the sample index is larger than this, something is likely wrong */
89 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (50*1024*1024)
91 /* For converting qt creation times to unix epoch times */
92 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
93 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
94 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
95 QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
97 #define QTDEMUX_TREE_NODE_FOURCC(n) (QT_FOURCC(((guint8 *) (n)->data) + 4))
99 #define STREAM_IS_EOS(s) (s->time_position == GST_CLOCK_TIME_NONE)
101 #define ABSDIFF(x, y) ( (x) > (y) ? ((x) - (y)) : ((y) - (x)) )
103 GST_DEBUG_CATEGORY (qtdemux_debug);
105 typedef struct _QtDemuxSegment QtDemuxSegment;
106 typedef struct _QtDemuxSample QtDemuxSample;
108 typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo;
110 struct _QtDemuxSample
113 gint32 pts_offset; /* Add this value to timestamp to get the pts */
115 guint64 timestamp; /* DTS In mov time */
116 guint32 duration; /* In mov time */
117 gboolean keyframe; /* TRUE when this packet is a keyframe */
120 /* Macros for converting to/from timescale */
121 #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale))
122 #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND))
124 #define QTTIME_TO_GSTTIME(qtdemux, value) (gst_util_uint64_scale((value), GST_SECOND, (qtdemux)->timescale))
125 #define GSTTIME_TO_QTTIME(qtdemux, value) (gst_util_uint64_scale((value), (qtdemux)->timescale, GST_SECOND))
127 /* timestamp is the DTS */
128 #define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp))
129 /* timestamp + offset + cslg_shift is the outgoing PTS */
130 #define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (stream)->cslg_shift + (sample)->pts_offset))
131 /* timestamp + offset is the PTS used for internal seek calcuations */
132 #define QTSAMPLE_PTS_NO_CSLG(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (sample)->pts_offset))
133 /* timestamp + duration - dts is the duration */
134 #define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts))
136 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
139 * Quicktime has tracks and segments. A track is a continuous piece of
140 * multimedia content. The track is not always played from start to finish but
141 * instead, pieces of the track are 'cut out' and played in sequence. This is
142 * what the segments do.
144 * Inside the track we have keyframes (K) and delta frames. The track has its
145 * own timing, which starts from 0 and extends to end. The position in the track
146 * is called the media_time.
148 * The segments now describe the pieces that should be played from this track
149 * and are basically tuples of media_time/duration/rate entries. We can have
150 * multiple segments and they are all played after one another. An example:
152 * segment 1: media_time: 1 second, duration: 1 second, rate 1
153 * segment 2: media_time: 3 second, duration: 2 second, rate 2
155 * To correctly play back this track, one must play: 1 second of media starting
156 * from media_time 1 followed by 2 seconds of media starting from media_time 3
159 * Each of the segments will be played at a specific time, the first segment at
160 * time 0, the second one after the duration of the first one, etc.. Note that
161 * the time in resulting playback is not identical to the media_time of the
164 * Visually, assuming the track has 4 second of media_time:
167 * .-----------------------------------------------------------.
168 * track: | K.....K.........K........K.......K.......K...........K... |
169 * '-----------------------------------------------------------'
171 * .------------^ ^ .----------^ ^
172 * / .-------------' / .------------------'
174 * .--------------. .--------------.
175 * | segment 1 | | segment 2 |
176 * '--------------' '--------------'
178 * The challenge here is to cut out the right pieces of the track for each of
179 * the playback segments. This fortunately can easily be done with the SEGMENT
180 * events of GStreamer.
182 * For playback of segment 1, we need to provide the decoder with the keyframe
183 * (a), in the above figure, but we must instruct it only to output the decoded
184 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
185 * position set to the time of the segment: 0.
187 * We then proceed to push data from keyframe (a) to frame (b). The decoder
188 * decodes but clips all before media_time 1.
190 * After finishing a segment, we push out a new SEGMENT event with the clipping
191 * boundaries of the new data.
193 * This is a good usecase for the GStreamer accumulated SEGMENT events.
196 struct _QtDemuxSegment
198 /* global time and duration, all gst time */
200 GstClockTime stop_time;
201 GstClockTime duration;
202 /* media time of trak, all gst time */
203 GstClockTime media_start;
204 GstClockTime media_stop;
206 /* Media start time in trak timescale units */
207 guint32 trak_media_start;
210 #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
212 /* Used with fragmented MP4 files (mfra atom) */
217 } QtDemuxRandomAccessEntry;
219 struct _QtDemuxStream
229 gboolean new_caps; /* If TRUE, caps need to be generated (by
230 * calling _configure_stream()) This happens
231 * for MSS and fragmented streams */
233 gboolean new_stream; /* signals that a stream_start is required */
234 gboolean on_keyframe; /* if this stream last pushed buffer was a
235 * keyframe. This is important to identify
236 * where to stop pushing buffers after a
237 * segment stop time */
239 /* if the stream has a redirect URI in its headers, we store it here */
246 guint64 duration; /* in timescale units */
250 gchar lang_id[4]; /* ISO 639-2T language code */
254 QtDemuxSample *samples;
255 gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */
256 guint32 first_duration; /* duration in timescale of first sample, used for figuring out
258 guint32 n_samples_moof; /* sample count in a moof */
259 guint64 duration_moof; /* duration in timescale of a moof, used for figure out
260 * the framerate of fragmented format stream */
261 guint64 duration_last_moof;
263 guint32 offset_in_sample; /* Offset in the current sample, used for
264 * streams which have got exceedingly big
265 * sample size (such as 24s of raw audio).
266 * Only used when max_buffer_size is non-NULL */
267 guint32 max_buffer_size; /* Maximum allowed size for output buffers.
268 * Currently only set for raw audio streams*/
270 /* if we use chunks or samples */
282 /* Numerator/denominator framerate */
285 GstVideoColorimetry colorimetry;
286 guint16 bits_per_sample;
287 guint16 color_table_id;
288 GstMemory *rgb8_palette;
289 guint interlace_mode;
295 guint samples_per_packet;
296 guint samples_per_frame;
297 guint bytes_per_packet;
298 guint bytes_per_sample;
299 guint bytes_per_frame;
303 gboolean use_allocator;
304 GstAllocator *allocator;
305 GstAllocationParams params;
309 /* when a discontinuity is pending */
312 /* list of buffers to push first */
315 /* if we need to clip this buffer. This is only needed for uncompressed
319 /* buffer needs some custom processing, e.g. subtitles */
320 gboolean need_process;
322 /* current position */
323 guint32 segment_index;
324 guint32 sample_index;
325 GstClockTime time_position; /* in gst time */
326 guint64 accumulated_base;
328 /* the Gst segment we are processing out, used for clipping */
331 /* quicktime segments */
333 QtDemuxSegment *segments;
334 gboolean dummy_segment;
339 GstTagList *stream_tags;
340 gboolean send_global_tags;
342 GstEvent *pending_event;
352 gboolean chunks_are_samples; /* TRUE means treat chunks as samples */
356 GstByteReader co_chunk;
358 guint32 current_chunk;
360 guint32 samples_per_chunk;
361 guint32 stco_sample_index;
363 guint32 sample_size; /* 0 means variable sizes are stored in stsz */
366 guint32 n_samples_per_chunk;
367 guint32 stsc_chunk_index;
368 guint32 stsc_sample_index;
369 guint64 chunk_offset;
372 guint32 stts_samples;
373 guint32 n_sample_times;
374 guint32 stts_sample_index;
376 guint32 stts_duration;
378 gboolean stss_present;
379 guint32 n_sample_syncs;
382 gboolean stps_present;
383 guint32 n_sample_partial_syncs;
385 QtDemuxRandomAccessEntry *ra_entries;
388 const QtDemuxRandomAccessEntry *pending_seek;
391 gboolean ctts_present;
392 guint32 n_composition_times;
394 guint32 ctts_sample_index;
402 gboolean parsed_trex;
403 guint32 def_sample_duration;
404 guint32 def_sample_size;
405 guint32 def_sample_flags;
409 /* stereoscopic video streams */
410 GstVideoMultiviewMode multiview_mode;
411 GstVideoMultiviewFlags multiview_flags;
413 /* protected streams */
415 guint32 protection_scheme_type;
416 guint32 protection_scheme_version;
417 gpointer protection_scheme_info; /* specific to the protection scheme */
418 GQueue protection_scheme_event_queue;
421 /* Contains properties and cryptographic info for a set of samples from a
422 * track protected using Common Encryption (cenc) */
423 struct _QtDemuxCencSampleSetInfo
425 GstStructure *default_properties;
427 /* @crypto_info holds one GstStructure per sample */
428 GPtrArray *crypto_info;
432 qt_demux_state_string (enum QtDemuxState state)
435 case QTDEMUX_STATE_INITIAL:
437 case QTDEMUX_STATE_HEADER:
439 case QTDEMUX_STATE_MOVIE:
441 case QTDEMUX_STATE_BUFFER_MDAT:
442 return "<BUFFER_MDAT>";
448 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
449 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
450 guint32 fourcc, GstByteReader * parser);
451 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
452 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
453 guint32 fourcc, GstByteReader * parser);
455 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
457 static GstStaticPadTemplate gst_qtdemux_sink_template =
458 GST_STATIC_PAD_TEMPLATE ("sink",
461 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
465 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
466 GST_STATIC_PAD_TEMPLATE ("video_%u",
469 GST_STATIC_CAPS_ANY);
471 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
472 GST_STATIC_PAD_TEMPLATE ("audio_%u",
475 GST_STATIC_CAPS_ANY);
477 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
478 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
481 GST_STATIC_CAPS_ANY);
483 #define gst_qtdemux_parent_class parent_class
484 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
486 static void gst_qtdemux_dispose (GObject * object);
489 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
490 GstClockTime media_time);
492 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
493 QtDemuxStream * str, gint64 media_offset);
496 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
497 static GstIndex *gst_qtdemux_get_index (GstElement * element);
499 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
500 GstStateChange transition);
501 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
502 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
503 GstObject * parent, GstPadMode mode, gboolean active);
505 static void gst_qtdemux_loop (GstPad * pad);
506 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
508 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
510 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
511 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
512 QtDemuxStream * stream);
513 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
516 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
517 const guint8 * buffer, guint length);
518 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
519 const guint8 * buffer, guint length);
520 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
521 static void qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist,
524 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
525 QtDemuxStream * stream, GNode * esds, GstTagList * list);
526 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
527 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
528 gchar ** codec_name);
529 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
530 QtDemuxStream * stream, guint32 fourcc, const guint8 * data, int len,
531 gchar ** codec_name);
532 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux,
533 QtDemuxStream * stream, guint32 fourcc, const guint8 * data,
534 gchar ** codec_name);
535 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
536 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
537 gchar ** codec_name);
539 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
540 QtDemuxStream * stream, guint32 n);
541 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
542 static void gst_qtdemux_stream_free (GstQTDemux * qtdemux,
543 QtDemuxStream * stream);
544 static void gst_qtdemux_stream_clear (GstQTDemux * qtdemux,
545 QtDemuxStream * stream);
546 static void gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int index);
547 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
548 static void qtdemux_do_allocation (GstQTDemux * qtdemux,
549 QtDemuxStream * stream);
550 static gboolean gst_qtdemux_activate_segment (GstQTDemux * qtdemux,
551 QtDemuxStream * stream, guint32 seg_idx, GstClockTime offset);
552 static gboolean gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux,
553 QtDemuxStream * stream, gint seg_idx, GstClockTime offset,
554 GstClockTime * _start, GstClockTime * _stop);
555 static void gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
556 QtDemuxStream * stream, gint segment_index, GstClockTime pos);
558 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
559 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
561 static gchar *qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes);
563 static GstStructure *qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
564 QtDemuxStream * stream, guint sample_index);
565 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
567 static void qtdemux_gst_structure_free (GstStructure * gststructure);
570 gst_qtdemux_class_init (GstQTDemuxClass * klass)
572 GObjectClass *gobject_class;
573 GstElementClass *gstelement_class;
575 gobject_class = (GObjectClass *) klass;
576 gstelement_class = (GstElementClass *) klass;
578 parent_class = g_type_class_peek_parent (klass);
580 gobject_class->dispose = gst_qtdemux_dispose;
582 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
584 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
585 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
588 gst_tag_register_musicbrainz_tags ();
590 gst_element_class_add_static_pad_template (gstelement_class,
591 &gst_qtdemux_sink_template);
592 gst_element_class_add_static_pad_template (gstelement_class,
593 &gst_qtdemux_videosrc_template);
594 gst_element_class_add_static_pad_template (gstelement_class,
595 &gst_qtdemux_audiosrc_template);
596 gst_element_class_add_static_pad_template (gstelement_class,
597 &gst_qtdemux_subsrc_template);
598 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
600 "Demultiplex a QuickTime file into audio and video streams",
601 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
603 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
608 gst_qtdemux_init (GstQTDemux * qtdemux)
611 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
612 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
613 gst_pad_set_activatemode_function (qtdemux->sinkpad,
614 qtdemux_sink_activate_mode);
615 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
616 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
617 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
619 qtdemux->state = QTDEMUX_STATE_INITIAL;
620 qtdemux->pullbased = FALSE;
621 qtdemux->posted_redirect = FALSE;
622 qtdemux->neededbytes = 16;
624 qtdemux->adapter = gst_adapter_new ();
626 qtdemux->first_mdat = -1;
627 qtdemux->got_moov = FALSE;
628 qtdemux->mdatoffset = -1;
629 qtdemux->mdatbuffer = NULL;
630 qtdemux->restoredata_buffer = NULL;
631 qtdemux->restoredata_offset = -1;
632 qtdemux->fragment_start = -1;
633 qtdemux->fragment_start_offset = -1;
634 qtdemux->media_caps = NULL;
635 qtdemux->exposed = FALSE;
636 qtdemux->mss_mode = FALSE;
637 qtdemux->pending_newsegment = NULL;
638 qtdemux->upstream_format_is_time = FALSE;
639 qtdemux->have_group_id = FALSE;
640 qtdemux->group_id = G_MAXUINT;
641 qtdemux->cenc_aux_info_offset = 0;
642 qtdemux->cenc_aux_info_sizes = NULL;
643 qtdemux->cenc_aux_sample_count = 0;
644 qtdemux->protection_system_ids = NULL;
645 g_queue_init (&qtdemux->protection_event_queue);
646 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
647 qtdemux->tag_list = gst_tag_list_new_empty ();
648 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
649 qtdemux->flowcombiner = gst_flow_combiner_new ();
651 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
655 gst_qtdemux_dispose (GObject * object)
657 GstQTDemux *qtdemux = GST_QTDEMUX (object);
659 if (qtdemux->adapter) {
660 g_object_unref (G_OBJECT (qtdemux->adapter));
661 qtdemux->adapter = NULL;
663 gst_tag_list_unref (qtdemux->tag_list);
664 gst_flow_combiner_free (qtdemux->flowcombiner);
665 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
667 g_queue_clear (&qtdemux->protection_event_queue);
669 g_free (qtdemux->cenc_aux_info_sizes);
670 qtdemux->cenc_aux_info_sizes = NULL;
672 G_OBJECT_CLASS (parent_class)->dispose (object);
676 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
678 if (qtdemux->posted_redirect) {
679 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
680 (_("This file contains no playable streams.")),
681 ("no known streams found, a redirect message has been posted"));
683 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
684 (_("This file contains no playable streams.")),
685 ("no known streams found"));
690 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
692 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
693 mem, size, 0, size, mem, free_func);
697 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
704 if (G_UNLIKELY (size == 0)) {
706 GstBuffer *tmp = NULL;
708 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
709 if (ret != GST_FLOW_OK)
712 gst_buffer_map (tmp, &map, GST_MAP_READ);
713 size = QT_UINT32 (map.data);
714 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
716 gst_buffer_unmap (tmp, &map);
717 gst_buffer_unref (tmp);
720 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
721 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
722 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
723 /* we're pulling header but already got most interesting bits,
724 * so never mind the rest (e.g. tags) (that much) */
725 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
729 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
730 (_("This file is invalid and cannot be played.")),
731 ("atom has bogus size %" G_GUINT64_FORMAT, size));
732 return GST_FLOW_ERROR;
736 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
738 if (G_UNLIKELY (flow != GST_FLOW_OK))
741 bsize = gst_buffer_get_size (*buf);
742 /* Catch short reads - we don't want any partial atoms */
743 if (G_UNLIKELY (bsize < size)) {
744 GST_WARNING_OBJECT (qtdemux,
745 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
746 gst_buffer_unref (*buf);
756 gst_qtdemux_src_convert (GstQTDemux * qtdemux, GstPad * pad,
757 GstFormat src_format, gint64 src_value, GstFormat dest_format,
761 QtDemuxStream *stream = gst_pad_get_element_private (pad);
764 if (stream->subtype != FOURCC_vide) {
769 switch (src_format) {
770 case GST_FORMAT_TIME:
771 switch (dest_format) {
772 case GST_FORMAT_BYTES:{
773 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
779 *dest_value = stream->samples[index].offset;
781 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
782 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
783 GST_TIME_ARGS (src_value), *dest_value);
791 case GST_FORMAT_BYTES:
792 switch (dest_format) {
793 case GST_FORMAT_TIME:{
795 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
804 QTSTREAMTIME_TO_GSTTIME (stream,
805 stream->samples[index].timestamp);
806 GST_DEBUG_OBJECT (qtdemux,
807 "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
808 GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
827 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
829 gboolean res = FALSE;
831 *duration = GST_CLOCK_TIME_NONE;
833 if (qtdemux->duration != 0 &&
834 qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
835 *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
838 *duration = GST_CLOCK_TIME_NONE;
845 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
848 gboolean res = FALSE;
849 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
851 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
853 switch (GST_QUERY_TYPE (query)) {
854 case GST_QUERY_POSITION:{
857 gst_query_parse_position (query, &fmt, NULL);
858 if (fmt == GST_FORMAT_TIME
859 && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
860 gst_query_set_position (query, GST_FORMAT_TIME,
861 qtdemux->segment.position);
866 case GST_QUERY_DURATION:{
869 gst_query_parse_duration (query, &fmt, NULL);
870 if (fmt == GST_FORMAT_TIME) {
871 /* First try to query upstream */
872 res = gst_pad_query_default (pad, parent, query);
874 GstClockTime duration;
875 if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
876 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
883 case GST_QUERY_CONVERT:{
884 GstFormat src_fmt, dest_fmt;
885 gint64 src_value, dest_value = 0;
887 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
889 res = gst_qtdemux_src_convert (qtdemux, pad,
890 src_fmt, src_value, dest_fmt, &dest_value);
892 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
897 case GST_QUERY_FORMATS:
898 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
901 case GST_QUERY_SEEKING:{
905 /* try upstream first */
906 res = gst_pad_query_default (pad, parent, query);
909 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
910 if (fmt == GST_FORMAT_TIME) {
911 GstClockTime duration;
913 gst_qtdemux_get_duration (qtdemux, &duration);
915 if (!qtdemux->pullbased) {
918 /* we might be able with help from upstream */
920 q = gst_query_new_seeking (GST_FORMAT_BYTES);
921 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
922 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
923 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
927 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
933 case GST_QUERY_SEGMENT:
938 format = qtdemux->segment.format;
941 gst_segment_to_stream_time (&qtdemux->segment, format,
942 qtdemux->segment.start);
943 if ((stop = qtdemux->segment.stop) == -1)
944 stop = qtdemux->segment.duration;
946 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
948 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
953 res = gst_pad_query_default (pad, parent, query);
961 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
963 if (G_LIKELY (stream->pad)) {
964 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
965 GST_DEBUG_PAD_NAME (stream->pad));
967 if (!gst_tag_list_is_empty (stream->stream_tags)) {
968 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
969 stream->stream_tags);
970 gst_pad_push_event (stream->pad,
971 gst_event_new_tag (gst_tag_list_ref (stream->stream_tags)));
974 if (G_UNLIKELY (stream->send_global_tags)) {
975 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
977 gst_pad_push_event (stream->pad,
978 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
979 stream->send_global_tags = FALSE;
984 /* push event on all source pads; takes ownership of the event */
986 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
989 gboolean has_valid_stream = FALSE;
990 GstEventType etype = GST_EVENT_TYPE (event);
992 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
993 GST_EVENT_TYPE_NAME (event));
995 for (n = 0; n < qtdemux->n_streams; n++) {
997 QtDemuxStream *stream = qtdemux->streams[n];
998 GST_DEBUG_OBJECT (qtdemux, "pushing on pad %i", n);
1000 if ((pad = stream->pad)) {
1001 has_valid_stream = TRUE;
1003 if (etype == GST_EVENT_EOS) {
1004 /* let's not send twice */
1005 if (stream->sent_eos)
1007 stream->sent_eos = TRUE;
1010 gst_pad_push_event (pad, gst_event_ref (event));
1014 gst_event_unref (event);
1016 /* if it is EOS and there are no pads, post an error */
1017 if (!has_valid_stream && etype == GST_EVENT_EOS) {
1018 gst_qtdemux_post_no_playable_stream_error (qtdemux);
1022 /* push a pending newsegment event, if any from the streaming thread */
1024 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
1026 if (qtdemux->pending_newsegment) {
1027 gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
1028 qtdemux->pending_newsegment = NULL;
1038 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
1040 if ((gint64) s1->timestamp + s1->pts_offset > *media_time)
1042 if ((gint64) s1->timestamp + s1->pts_offset == *media_time)
1048 /* find the index of the sample that includes the data for @media_time using a
1049 * binary search. Only to be called in optimized cases of linear search below.
1051 * Returns the index of the sample.
1054 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
1057 QtDemuxSample *result;
1060 /* convert media_time to mov format */
1062 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1064 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
1065 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
1066 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
1068 if (G_LIKELY (result))
1069 index = result - str->samples;
1078 /* find the index of the sample that includes the data for @media_offset using a
1081 * Returns the index of the sample.
1084 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
1085 QtDemuxStream * str, gint64 media_offset)
1087 QtDemuxSample *result = str->samples;
1090 if (result == NULL || str->n_samples == 0)
1093 if (media_offset == result->offset)
1097 while (index < str->n_samples - 1) {
1098 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1101 if (media_offset < result->offset)
1112 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1117 /* find the index of the sample that includes the data for @media_time using a
1118 * linear search, and keeping in mind that not all samples may have been parsed
1119 * yet. If possible, it will delegate to binary search.
1121 * Returns the index of the sample.
1124 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
1125 GstClockTime media_time)
1129 QtDemuxSample *sample;
1131 /* convert media_time to mov format */
1133 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1135 sample = str->samples;
1136 if (mov_time == sample->timestamp + sample->pts_offset)
1139 /* use faster search if requested time in already parsed range */
1140 sample = str->samples + str->stbl_index;
1141 if (str->stbl_index >= 0 &&
1142 mov_time <= (sample->timestamp + sample->pts_offset))
1143 return gst_qtdemux_find_index (qtdemux, str, media_time);
1145 while (index < str->n_samples - 1) {
1146 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1149 sample = str->samples + index + 1;
1150 if (mov_time < (sample->timestamp + sample->pts_offset))
1160 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1165 /* find the index of the keyframe needed to decode the sample at @index
1166 * of stream @str, or of a subsequent keyframe (depending on @next)
1168 * Returns the index of the keyframe.
1171 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1172 guint32 index, gboolean next)
1174 guint32 new_index = index;
1176 if (index >= str->n_samples) {
1177 new_index = str->n_samples;
1181 /* all keyframes, return index */
1182 if (str->all_keyframe) {
1187 /* else search until we have a keyframe */
1188 while (new_index < str->n_samples) {
1189 if (next && !qtdemux_parse_samples (qtdemux, str, new_index))
1192 if (str->samples[new_index].keyframe)
1204 if (new_index == str->n_samples) {
1205 GST_DEBUG_OBJECT (qtdemux, "no next keyframe");
1210 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index %s index %u "
1211 "gave %u", next ? "after" : "before", index, new_index);
1218 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", new_index);
1223 /* find the segment for @time_position for @stream
1225 * Returns the index of the segment containing @time_position.
1226 * Returns the last segment and sets the @eos variable to TRUE
1227 * if the time is beyond the end. @eos may be NULL
1230 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1231 GstClockTime time_position)
1236 GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1237 GST_TIME_ARGS (time_position));
1240 for (i = 0; i < stream->n_segments; i++) {
1241 QtDemuxSegment *segment = &stream->segments[i];
1243 GST_LOG_OBJECT (stream->pad,
1244 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1245 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1247 /* For the last segment we include stop_time in the last segment */
1248 if (i < stream->n_segments - 1) {
1249 if (segment->time <= time_position && time_position < segment->stop_time) {
1250 GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1255 /* Last segment always matches */
1263 /* move the stream @str to the sample position @index.
1265 * Updates @str->sample_index and marks discontinuity if needed.
1268 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1271 /* no change needed */
1272 if (index == str->sample_index)
1275 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1278 /* position changed, we have a discont */
1279 str->sample_index = index;
1280 str->offset_in_sample = 0;
1281 /* Each time we move in the stream we store the position where we are
1283 str->from_sample = index;
1284 str->discont = TRUE;
1288 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1289 gboolean use_sparse, gboolean next, gint64 * key_time, gint64 * key_offset)
1292 gint64 min_byte_offset = -1;
1295 min_offset = desired_time;
1297 /* for each stream, find the index of the sample in the segment
1298 * and move back to the previous keyframe. */
1299 for (n = 0; n < qtdemux->n_streams; n++) {
1301 guint32 index, kindex;
1303 GstClockTime media_start;
1304 GstClockTime media_time;
1305 GstClockTime seg_time;
1306 QtDemuxSegment *seg;
1307 gboolean empty_segment = FALSE;
1309 str = qtdemux->streams[n];
1311 if (str->sparse && !use_sparse)
1314 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1315 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1317 /* get segment and time in the segment */
1318 seg = &str->segments[seg_idx];
1319 seg_time = (desired_time - seg->time) * seg->rate;
1321 while (QTSEGMENT_IS_EMPTY (seg)) {
1323 empty_segment = TRUE;
1324 GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1327 if (seg_idx == str->n_segments)
1329 seg = &str->segments[seg_idx];
1332 if (seg_idx == str->n_segments) {
1333 /* FIXME track shouldn't have the last segment as empty, but if it
1334 * happens we better handle it */
1338 /* get the media time in the segment */
1339 media_start = seg->media_start + seg_time;
1341 /* get the index of the sample with media time */
1342 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1343 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1344 " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1345 GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1348 /* shift to next frame if we are looking for next keyframe */
1349 if (next && QTSAMPLE_PTS_NO_CSLG (str, &str->samples[index]) < media_start
1350 && index < str->stbl_index)
1353 if (!empty_segment) {
1354 /* find previous keyframe */
1355 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, next);
1357 /* we will settle for one before if none found after */
1358 if (next && kindex == -1)
1359 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
1361 /* if the keyframe is at a different position, we need to update the
1362 * requested seek time */
1363 if (index != kindex) {
1366 /* get timestamp of keyframe */
1367 media_time = QTSAMPLE_PTS_NO_CSLG (str, &str->samples[kindex]);
1368 GST_DEBUG_OBJECT (qtdemux,
1369 "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1370 G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1371 str->samples[kindex].offset);
1373 /* keyframes in the segment get a chance to change the
1374 * desired_offset. keyframes out of the segment are
1376 if (media_time >= seg->media_start) {
1377 GstClockTime seg_time;
1379 /* this keyframe is inside the segment, convert back to
1381 seg_time = (media_time - seg->media_start) + seg->time;
1382 if ((!next && (seg_time < min_offset)) ||
1383 (next && (seg_time > min_offset)))
1384 min_offset = seg_time;
1389 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1390 min_byte_offset = str->samples[index].offset;
1394 *key_time = min_offset;
1396 *key_offset = min_byte_offset;
1400 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1401 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1405 g_return_val_if_fail (format != NULL, FALSE);
1406 g_return_val_if_fail (cur != NULL, FALSE);
1407 g_return_val_if_fail (stop != NULL, FALSE);
1409 if (*format == GST_FORMAT_TIME)
1413 if (cur_type != GST_SEEK_TYPE_NONE)
1414 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1415 if (res && stop_type != GST_SEEK_TYPE_NONE)
1416 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1419 *format = GST_FORMAT_TIME;
1424 /* perform seek in push based mode:
1425 find BYTE position to move to based on time and delegate to upstream
1428 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1433 GstSeekType cur_type, stop_type;
1434 gint64 cur, stop, key_cur;
1437 gint64 original_stop;
1440 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1442 gst_event_parse_seek (event, &rate, &format, &flags,
1443 &cur_type, &cur, &stop_type, &stop);
1444 seqnum = gst_event_get_seqnum (event);
1446 /* only forward streaming and seeking is possible */
1448 goto unsupported_seek;
1450 /* convert to TIME if needed and possible */
1451 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1455 /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1456 * the original stop position to use when upstream pushes the new segment
1458 original_stop = stop;
1461 /* find reasonable corresponding BYTE position,
1462 * also try to mind about keyframes, since we can not go back a bit for them
1464 /* determining @next here based on SNAP_BEFORE/SNAP_AFTER should
1465 * mostly just work, but let's not yet boldly go there ... */
1466 gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, FALSE, &key_cur, &byte_cur);
1471 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1472 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1475 GST_OBJECT_LOCK (qtdemux);
1476 qtdemux->seek_offset = byte_cur;
1477 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1478 qtdemux->push_seek_start = cur;
1480 qtdemux->push_seek_start = key_cur;
1483 if (stop_type == GST_SEEK_TYPE_NONE) {
1484 qtdemux->push_seek_stop = qtdemux->segment.stop;
1486 qtdemux->push_seek_stop = original_stop;
1488 GST_OBJECT_UNLOCK (qtdemux);
1490 /* BYTE seek event */
1491 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1493 gst_event_set_seqnum (event, seqnum);
1494 res = gst_pad_push_event (qtdemux->sinkpad, event);
1501 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1507 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1512 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1517 /* perform the seek.
1519 * We set all segment_indexes in the streams to unknown and
1520 * adjust the time_position to the desired position. this is enough
1521 * to trigger a segment switch in the streaming thread to start
1522 * streaming from the desired position.
1524 * Keyframe seeking is a little more complicated when dealing with
1525 * segments. Ideally we want to move to the previous keyframe in
1526 * the segment but there might not be a keyframe in the segment. In
1527 * fact, none of the segments could contain a keyframe. We take a
1528 * practical approach: seek to the previous keyframe in the segment,
1529 * if there is none, seek to the beginning of the segment.
1531 * Called with STREAM_LOCK
1534 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1535 guint32 seqnum, GstSeekFlags flags)
1537 gint64 desired_offset;
1540 desired_offset = segment->position;
1542 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1543 GST_TIME_ARGS (desired_offset));
1545 /* may not have enough fragmented info to do this adjustment,
1546 * and we can't scan (and probably should not) at this time with
1547 * possibly flushing upstream */
1548 if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1550 gboolean next, before, after;
1552 before = ! !(flags & GST_SEEK_FLAG_SNAP_BEFORE);
1553 after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER);
1554 next = after && !before;
1555 if (segment->rate < 0)
1558 gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, next, &min_offset,
1560 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1561 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1562 desired_offset = min_offset;
1565 /* and set all streams to the final position */
1566 gst_flow_combiner_reset (qtdemux->flowcombiner);
1567 qtdemux->segment_seqnum = seqnum;
1568 for (n = 0; n < qtdemux->n_streams; n++) {
1569 QtDemuxStream *stream = qtdemux->streams[n];
1571 stream->time_position = desired_offset;
1572 stream->accumulated_base = 0;
1573 stream->sample_index = -1;
1574 stream->offset_in_sample = 0;
1575 stream->segment_index = -1;
1576 stream->sent_eos = FALSE;
1578 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1579 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1581 segment->position = desired_offset;
1582 segment->time = desired_offset;
1583 if (segment->rate >= 0) {
1584 segment->start = desired_offset;
1586 /* we stop at the end */
1587 if (segment->stop == -1)
1588 segment->stop = segment->duration;
1590 segment->stop = desired_offset;
1593 if (qtdemux->fragmented)
1594 qtdemux->fragmented_seek_pending = TRUE;
1599 /* do a seek in pull based mode */
1601 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1606 GstSeekType cur_type, stop_type;
1610 GstSegment seeksegment;
1612 GstEvent *flush_event;
1615 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1617 gst_event_parse_seek (event, &rate, &format, &flags,
1618 &cur_type, &cur, &stop_type, &stop);
1619 seqnum = gst_event_get_seqnum (event);
1621 /* we have to have a format as the segment format. Try to convert
1623 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1627 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1629 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1633 flush = flags & GST_SEEK_FLAG_FLUSH;
1635 /* stop streaming, either by flushing or by pausing the task */
1637 flush_event = gst_event_new_flush_start ();
1639 gst_event_set_seqnum (flush_event, seqnum);
1640 /* unlock upstream pull_range */
1641 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1642 /* make sure out loop function exits */
1643 gst_qtdemux_push_event (qtdemux, flush_event);
1645 /* non flushing seek, pause the task */
1646 gst_pad_pause_task (qtdemux->sinkpad);
1649 /* wait for streaming to finish */
1650 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1652 /* copy segment, we need this because we still need the old
1653 * segment when we close the current segment. */
1654 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1657 /* configure the segment with the seek variables */
1658 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1659 gst_segment_do_seek (&seeksegment, rate, format, flags,
1660 cur_type, cur, stop_type, stop, &update);
1663 /* now do the seek, this actually never returns FALSE */
1664 gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1666 /* prepare for streaming again */
1668 flush_event = gst_event_new_flush_stop (TRUE);
1670 gst_event_set_seqnum (flush_event, seqnum);
1672 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1673 gst_qtdemux_push_event (qtdemux, flush_event);
1676 /* commit the new segment */
1677 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1679 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1680 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1681 qtdemux->segment.format, qtdemux->segment.position);
1683 gst_message_set_seqnum (msg, seqnum);
1684 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1687 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1688 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1689 qtdemux->sinkpad, NULL);
1691 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1698 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1704 qtdemux_ensure_index (GstQTDemux * qtdemux)
1708 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1710 /* Build complete index */
1711 for (i = 0; i < qtdemux->n_streams; i++) {
1712 QtDemuxStream *stream = qtdemux->streams[i];
1714 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1722 GST_LOG_OBJECT (qtdemux,
1723 "Building complete index of stream %u for seeking failed!", i);
1729 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1732 gboolean res = TRUE;
1733 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1735 switch (GST_EVENT_TYPE (event)) {
1736 case GST_EVENT_SEEK:
1738 #ifndef GST_DISABLE_GST_DEBUG
1739 GstClockTime ts = gst_util_get_timestamp ();
1741 guint32 seqnum = gst_event_get_seqnum (event);
1743 if (seqnum == qtdemux->segment_seqnum) {
1744 GST_LOG_OBJECT (pad,
1745 "Drop duplicated SEEK event seqnum %" G_GUINT32_FORMAT, seqnum);
1746 gst_event_unref (event);
1750 if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1751 /* seek should be handled by upstream, we might need to re-download fragments */
1752 GST_DEBUG_OBJECT (qtdemux,
1753 "let upstream handle seek for fragmented playback");
1757 /* Build complete index for seeking;
1758 * if not a fragmented file at least */
1759 if (!qtdemux->fragmented)
1760 if (!qtdemux_ensure_index (qtdemux))
1762 #ifndef GST_DISABLE_GST_DEBUG
1763 ts = gst_util_get_timestamp () - ts;
1764 GST_INFO_OBJECT (qtdemux,
1765 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1768 if (qtdemux->pullbased) {
1769 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1770 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1771 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1773 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams
1774 && !qtdemux->fragmented) {
1775 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1777 GST_DEBUG_OBJECT (qtdemux,
1778 "ignoring seek in push mode in current state");
1781 gst_event_unref (event);
1785 res = gst_pad_event_default (pad, parent, event);
1795 GST_ERROR_OBJECT (qtdemux, "Index failed");
1796 gst_event_unref (event);
1802 /* stream/index return sample that is min/max w.r.t. byte position,
1803 * time is min/max w.r.t. time of samples,
1804 * the latter need not be time of the former sample */
1806 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1807 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1810 gint64 time, min_time;
1811 QtDemuxStream *stream;
1817 for (n = 0; n < qtdemux->n_streams; ++n) {
1820 gboolean set_sample;
1822 str = qtdemux->streams[n];
1829 i = str->n_samples - 1;
1833 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1834 if (str->samples[i].size == 0)
1837 if (fw && (str->samples[i].offset < byte_pos))
1840 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1843 /* move stream to first available sample */
1845 gst_qtdemux_move_stream (qtdemux, str, i);
1849 /* avoid index from sparse streams since they might be far away */
1851 /* determine min/max time */
1852 time = QTSAMPLE_PTS (str, &str->samples[i]);
1853 if (min_time == -1 || (!fw && time > min_time) ||
1854 (fw && time < min_time)) {
1858 /* determine stream with leading sample, to get its position */
1860 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1861 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1869 /* no sample for this stream, mark eos */
1871 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1882 static QtDemuxStream *
1883 _create_stream (void)
1885 QtDemuxStream *stream;
1887 stream = g_new0 (QtDemuxStream, 1);
1888 /* new streams always need a discont */
1889 stream->discont = TRUE;
1890 /* we enable clipping for raw audio/video streams */
1891 stream->need_clip = FALSE;
1892 stream->need_process = FALSE;
1893 stream->segment_index = -1;
1894 stream->time_position = 0;
1895 stream->sample_index = -1;
1896 stream->offset_in_sample = 0;
1897 stream->new_stream = TRUE;
1898 stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1899 stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1900 stream->protected = FALSE;
1901 stream->protection_scheme_type = 0;
1902 stream->protection_scheme_version = 0;
1903 stream->protection_scheme_info = NULL;
1904 stream->n_samples_moof = 0;
1905 stream->duration_moof = 0;
1906 stream->duration_last_moof = 0;
1907 stream->alignment = 1;
1908 stream->stream_tags = gst_tag_list_new_empty ();
1909 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
1910 g_queue_init (&stream->protection_scheme_event_queue);
1915 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1917 GstStructure *structure;
1918 const gchar *variant;
1919 const GstCaps *mediacaps = NULL;
1921 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1923 structure = gst_caps_get_structure (caps, 0);
1924 variant = gst_structure_get_string (structure, "variant");
1926 if (variant && strcmp (variant, "mss-fragmented") == 0) {
1927 QtDemuxStream *stream;
1928 const GValue *value;
1930 demux->fragmented = TRUE;
1931 demux->mss_mode = TRUE;
1933 if (demux->n_streams > 1) {
1934 /* can't do this, we can only renegotiate for another mss format */
1938 value = gst_structure_get_value (structure, "media-caps");
1941 const GValue *timescale_v;
1943 /* TODO update when stream changes during playback */
1945 if (demux->n_streams == 0) {
1946 stream = _create_stream ();
1947 demux->streams[demux->n_streams] = stream;
1948 demux->n_streams = 1;
1950 stream = demux->streams[0];
1953 timescale_v = gst_structure_get_value (structure, "timescale");
1955 stream->timescale = g_value_get_uint64 (timescale_v);
1957 /* default mss timescale */
1958 stream->timescale = 10000000;
1960 demux->timescale = stream->timescale;
1962 mediacaps = gst_value_get_caps (value);
1963 if (!stream->caps || !gst_caps_is_equal_fixed (mediacaps, stream->caps)) {
1964 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1966 stream->new_caps = TRUE;
1968 gst_caps_replace (&stream->caps, (GstCaps *) mediacaps);
1969 structure = gst_caps_get_structure (mediacaps, 0);
1970 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
1971 stream->subtype = FOURCC_vide;
1973 gst_structure_get_int (structure, "width", &stream->width);
1974 gst_structure_get_int (structure, "height", &stream->height);
1975 gst_structure_get_fraction (structure, "framerate", &stream->fps_n,
1977 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
1979 stream->subtype = FOURCC_soun;
1980 gst_structure_get_int (structure, "channels", &stream->n_channels);
1981 gst_structure_get_int (structure, "rate", &rate);
1982 stream->rate = rate;
1985 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
1987 demux->mss_mode = FALSE;
1994 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
1998 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
1999 gst_pad_stop_task (qtdemux->sinkpad);
2001 if (hard || qtdemux->upstream_format_is_time) {
2002 qtdemux->state = QTDEMUX_STATE_INITIAL;
2003 qtdemux->neededbytes = 16;
2004 qtdemux->todrop = 0;
2005 qtdemux->pullbased = FALSE;
2006 qtdemux->posted_redirect = FALSE;
2007 qtdemux->first_mdat = -1;
2008 qtdemux->header_size = 0;
2009 qtdemux->mdatoffset = -1;
2010 qtdemux->restoredata_offset = -1;
2011 if (qtdemux->mdatbuffer)
2012 gst_buffer_unref (qtdemux->mdatbuffer);
2013 if (qtdemux->restoredata_buffer)
2014 gst_buffer_unref (qtdemux->restoredata_buffer);
2015 qtdemux->mdatbuffer = NULL;
2016 qtdemux->restoredata_buffer = NULL;
2017 qtdemux->mdatleft = 0;
2018 qtdemux->mdatsize = 0;
2019 if (qtdemux->comp_brands)
2020 gst_buffer_unref (qtdemux->comp_brands);
2021 qtdemux->comp_brands = NULL;
2022 qtdemux->last_moov_offset = -1;
2023 if (qtdemux->moov_node_compressed) {
2024 g_node_destroy (qtdemux->moov_node_compressed);
2025 if (qtdemux->moov_node)
2026 g_free (qtdemux->moov_node->data);
2028 qtdemux->moov_node_compressed = NULL;
2029 if (qtdemux->moov_node)
2030 g_node_destroy (qtdemux->moov_node);
2031 qtdemux->moov_node = NULL;
2032 if (qtdemux->tag_list)
2033 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
2034 qtdemux->tag_list = gst_tag_list_new_empty ();
2035 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
2037 if (qtdemux->element_index)
2038 gst_object_unref (qtdemux->element_index);
2039 qtdemux->element_index = NULL;
2041 qtdemux->major_brand = 0;
2042 if (qtdemux->pending_newsegment)
2043 gst_event_unref (qtdemux->pending_newsegment);
2044 qtdemux->pending_newsegment = NULL;
2045 qtdemux->upstream_format_is_time = FALSE;
2046 qtdemux->upstream_seekable = FALSE;
2047 qtdemux->upstream_size = 0;
2049 qtdemux->fragment_start = -1;
2050 qtdemux->fragment_start_offset = -1;
2051 qtdemux->duration = 0;
2052 qtdemux->moof_offset = 0;
2053 qtdemux->chapters_track_id = 0;
2054 qtdemux->have_group_id = FALSE;
2055 qtdemux->group_id = G_MAXUINT;
2057 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
2059 g_queue_clear (&qtdemux->protection_event_queue);
2061 qtdemux->offset = 0;
2062 gst_adapter_clear (qtdemux->adapter);
2063 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
2064 qtdemux->segment_seqnum = 0;
2067 for (n = 0; n < qtdemux->n_streams; n++) {
2068 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
2069 qtdemux->streams[n] = NULL;
2071 qtdemux->n_streams = 0;
2072 qtdemux->n_video_streams = 0;
2073 qtdemux->n_audio_streams = 0;
2074 qtdemux->n_sub_streams = 0;
2075 qtdemux->exposed = FALSE;
2076 qtdemux->fragmented = FALSE;
2077 qtdemux->mss_mode = FALSE;
2078 gst_caps_replace (&qtdemux->media_caps, NULL);
2079 qtdemux->timescale = 0;
2080 qtdemux->got_moov = FALSE;
2081 if (qtdemux->protection_system_ids) {
2082 g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2083 qtdemux->protection_system_ids = NULL;
2085 } else if (qtdemux->mss_mode) {
2086 gst_flow_combiner_reset (qtdemux->flowcombiner);
2087 for (n = 0; n < qtdemux->n_streams; n++)
2088 gst_qtdemux_stream_clear (qtdemux, qtdemux->streams[n]);
2090 gst_flow_combiner_reset (qtdemux->flowcombiner);
2091 for (n = 0; n < qtdemux->n_streams; n++) {
2092 qtdemux->streams[n]->sent_eos = FALSE;
2093 qtdemux->streams[n]->time_position = 0;
2094 qtdemux->streams[n]->accumulated_base = 0;
2096 if (!qtdemux->pending_newsegment) {
2097 qtdemux->pending_newsegment = gst_event_new_segment (&qtdemux->segment);
2098 if (qtdemux->segment_seqnum)
2099 gst_event_set_seqnum (qtdemux->pending_newsegment,
2100 qtdemux->segment_seqnum);
2106 /* Maps the @segment to the qt edts internal segments and pushes
2107 * the correspnding segment event.
2109 * If it ends up being at a empty segment, a gap will be pushed and the next
2110 * edts segment will be activated in sequence.
2112 * To be used in push-mode only */
2114 gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
2118 for (n = 0; n < qtdemux->n_streams; n++) {
2119 QtDemuxStream *stream = qtdemux->streams[n];
2121 stream->time_position = segment->start;
2123 /* in push mode we should be guaranteed that we will have empty segments
2124 * at the beginning and then one segment after, other scenarios are not
2125 * supported and are discarded when parsing the edts */
2126 for (i = 0; i < stream->n_segments; i++) {
2127 if (stream->segments[i].stop_time > segment->start) {
2128 gst_qtdemux_activate_segment (qtdemux, stream, i,
2129 stream->time_position);
2130 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
2131 /* push the empty segment and move to the next one */
2132 gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
2133 stream->time_position);
2137 g_assert (i == stream->n_segments - 1);
2144 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2147 GstQTDemux *demux = GST_QTDEMUX (parent);
2148 gboolean res = TRUE;
2150 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2152 switch (GST_EVENT_TYPE (event)) {
2153 case GST_EVENT_SEGMENT:
2156 QtDemuxStream *stream;
2160 /* some debug output */
2161 gst_event_copy_segment (event, &segment);
2162 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2165 /* erase any previously set segment */
2166 gst_event_replace (&demux->pending_newsegment, NULL);
2168 if (segment.format == GST_FORMAT_TIME) {
2169 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
2170 gst_event_replace (&demux->pending_newsegment, event);
2171 demux->upstream_format_is_time = TRUE;
2173 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2174 "not in time format");
2176 /* chain will send initial newsegment after pads have been added */
2177 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
2178 GST_DEBUG_OBJECT (demux, "still starting, eating event");
2183 /* check if this matches a time seek we received previously
2184 * FIXME for backwards compatibility reasons we use the
2185 * seek_offset here to compare. In the future we might want to
2186 * change this to use the seqnum as it uniquely should identify
2187 * the segment that corresponds to the seek. */
2188 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2189 ", received segment offset %" G_GINT64_FORMAT,
2190 demux->seek_offset, segment.start);
2191 if (segment.format == GST_FORMAT_BYTES
2192 && demux->seek_offset == segment.start) {
2193 GST_OBJECT_LOCK (demux);
2194 offset = segment.start;
2196 segment.format = GST_FORMAT_TIME;
2197 segment.start = demux->push_seek_start;
2198 segment.stop = demux->push_seek_stop;
2199 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2200 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2201 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2202 GST_OBJECT_UNLOCK (demux);
2205 /* we only expect a BYTE segment, e.g. following a seek */
2206 if (segment.format == GST_FORMAT_BYTES) {
2207 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2208 offset = segment.start;
2210 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2211 NULL, (gint64 *) & segment.start);
2212 if ((gint64) segment.start < 0)
2215 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2216 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2217 NULL, (gint64 *) & segment.stop);
2218 /* keyframe seeking should already arrange for start >= stop,
2219 * but make sure in other rare cases */
2220 segment.stop = MAX (segment.stop, segment.start);
2222 } else if (segment.format == GST_FORMAT_TIME) {
2223 /* push all data on the adapter before starting this
2225 gst_qtdemux_process_adapter (demux, TRUE);
2227 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2231 /* We shouldn't modify upstream driven TIME FORMAT segment */
2232 if (!demux->upstream_format_is_time) {
2233 /* accept upstream's notion of segment and distribute along */
2234 segment.format = GST_FORMAT_TIME;
2235 segment.position = segment.time = segment.start;
2236 segment.duration = demux->segment.duration;
2237 segment.base = gst_segment_to_running_time (&demux->segment,
2238 GST_FORMAT_TIME, demux->segment.position);
2241 gst_segment_copy_into (&segment, &demux->segment);
2242 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2244 /* map segment to internal qt segments and push on each stream */
2245 if (demux->n_streams) {
2246 if (demux->fragmented) {
2247 GstEvent *segment_event = gst_event_new_segment (&segment);
2249 gst_event_replace (&demux->pending_newsegment, NULL);
2250 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
2251 gst_qtdemux_push_event (demux, segment_event);
2253 gst_event_replace (&demux->pending_newsegment, NULL);
2254 gst_qtdemux_map_and_push_segments (demux, &segment);
2258 /* clear leftover in current segment, if any */
2259 gst_adapter_clear (demux->adapter);
2261 /* set up streaming thread */
2262 demux->offset = offset;
2263 if (demux->upstream_format_is_time) {
2264 GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2265 "set values to restart reading from a new atom");
2266 demux->neededbytes = 16;
2269 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2272 demux->todrop = stream->samples[idx].offset - offset;
2273 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2275 /* set up for EOS */
2276 demux->neededbytes = -1;
2281 gst_event_unref (event);
2285 case GST_EVENT_FLUSH_START:
2287 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2288 gst_event_unref (event);
2293 case GST_EVENT_FLUSH_STOP:
2297 dur = demux->segment.duration;
2298 gst_qtdemux_reset (demux, FALSE);
2299 demux->segment.duration = dur;
2301 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2302 gst_event_unref (event);
2308 /* If we are in push mode, and get an EOS before we've seen any streams,
2309 * then error out - we have nowhere to send the EOS */
2310 if (!demux->pullbased) {
2312 gboolean has_valid_stream = FALSE;
2313 for (i = 0; i < demux->n_streams; i++) {
2314 if (demux->streams[i]->pad != NULL) {
2315 has_valid_stream = TRUE;
2319 if (!has_valid_stream)
2320 gst_qtdemux_post_no_playable_stream_error (demux);
2322 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2323 (guint) gst_adapter_available (demux->adapter));
2324 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2330 case GST_EVENT_CAPS:{
2331 GstCaps *caps = NULL;
2333 gst_event_parse_caps (event, &caps);
2334 gst_qtdemux_setcaps (demux, caps);
2336 gst_event_unref (event);
2339 case GST_EVENT_PROTECTION:
2341 const gchar *system_id = NULL;
2343 gst_event_parse_protection (event, &system_id, NULL, NULL);
2344 GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2346 gst_qtdemux_append_protection_system_id (demux, system_id);
2347 /* save the event for later, for source pads that have not been created */
2348 g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2349 /* send it to all pads that already exist */
2350 gst_qtdemux_push_event (demux, event);
2358 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2366 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2368 GstQTDemux *demux = GST_QTDEMUX (element);
2370 GST_OBJECT_LOCK (demux);
2371 if (demux->element_index)
2372 gst_object_unref (demux->element_index);
2374 demux->element_index = gst_object_ref (index);
2376 demux->element_index = NULL;
2378 GST_OBJECT_UNLOCK (demux);
2379 /* object lock might be taken again */
2381 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2382 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2383 demux->element_index, demux->index_id);
2387 gst_qtdemux_get_index (GstElement * element)
2389 GstIndex *result = NULL;
2390 GstQTDemux *demux = GST_QTDEMUX (element);
2392 GST_OBJECT_LOCK (demux);
2393 if (demux->element_index)
2394 result = gst_object_ref (demux->element_index);
2395 GST_OBJECT_UNLOCK (demux);
2397 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2404 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2406 g_free ((gpointer) stream->stco.data);
2407 stream->stco.data = NULL;
2408 g_free ((gpointer) stream->stsz.data);
2409 stream->stsz.data = NULL;
2410 g_free ((gpointer) stream->stsc.data);
2411 stream->stsc.data = NULL;
2412 g_free ((gpointer) stream->stts.data);
2413 stream->stts.data = NULL;
2414 g_free ((gpointer) stream->stss.data);
2415 stream->stss.data = NULL;
2416 g_free ((gpointer) stream->stps.data);
2417 stream->stps.data = NULL;
2418 g_free ((gpointer) stream->ctts.data);
2419 stream->ctts.data = NULL;
2423 gst_qtdemux_stream_flush_segments_data (GstQTDemux * qtdemux,
2424 QtDemuxStream * stream)
2426 g_free (stream->segments);
2427 stream->segments = NULL;
2428 stream->segment_index = -1;
2429 stream->accumulated_base = 0;
2433 gst_qtdemux_stream_flush_samples_data (GstQTDemux * qtdemux,
2434 QtDemuxStream * stream)
2436 g_free (stream->samples);
2437 stream->samples = NULL;
2438 gst_qtdemux_stbl_free (stream);
2441 g_free (stream->ra_entries);
2442 stream->ra_entries = NULL;
2443 stream->n_ra_entries = 0;
2445 stream->sample_index = -1;
2446 stream->stbl_index = -1;
2447 stream->n_samples = 0;
2448 stream->time_position = 0;
2450 stream->n_samples_moof = 0;
2451 stream->duration_moof = 0;
2452 stream->duration_last_moof = 0;
2456 gst_qtdemux_stream_clear (GstQTDemux * qtdemux, QtDemuxStream * stream)
2458 if (stream->allocator)
2459 gst_object_unref (stream->allocator);
2460 while (stream->buffers) {
2461 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2462 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2464 if (stream->rgb8_palette) {
2465 gst_memory_unref (stream->rgb8_palette);
2466 stream->rgb8_palette = NULL;
2469 gst_tag_list_unref (stream->stream_tags);
2470 stream->stream_tags = gst_tag_list_new_empty ();
2471 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
2472 g_free (stream->redirect_uri);
2473 stream->redirect_uri = NULL;
2474 stream->sent_eos = FALSE;
2475 stream->sparse = FALSE;
2476 stream->protected = FALSE;
2477 if (stream->protection_scheme_info) {
2478 if (stream->protection_scheme_type == FOURCC_cenc) {
2479 QtDemuxCencSampleSetInfo *info =
2480 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2481 if (info->default_properties)
2482 gst_structure_free (info->default_properties);
2483 if (info->crypto_info)
2484 g_ptr_array_free (info->crypto_info, TRUE);
2486 g_free (stream->protection_scheme_info);
2487 stream->protection_scheme_info = NULL;
2489 stream->protection_scheme_type = 0;
2490 stream->protection_scheme_version = 0;
2491 g_queue_foreach (&stream->protection_scheme_event_queue,
2492 (GFunc) gst_event_unref, NULL);
2493 g_queue_clear (&stream->protection_scheme_event_queue);
2494 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
2495 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
2499 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
2501 gst_qtdemux_stream_clear (qtdemux, stream);
2503 gst_caps_unref (stream->caps);
2504 stream->caps = NULL;
2505 gst_tag_list_unref (stream->stream_tags);
2507 gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
2508 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, stream->pad);
2514 gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int i)
2516 g_assert (i >= 0 && i < qtdemux->n_streams && qtdemux->streams[i] != NULL);
2518 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[i]);
2519 qtdemux->streams[i] = qtdemux->streams[qtdemux->n_streams - 1];
2520 qtdemux->streams[qtdemux->n_streams - 1] = NULL;
2521 qtdemux->n_streams--;
2524 static GstStateChangeReturn
2525 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2527 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2528 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2530 switch (transition) {
2531 case GST_STATE_CHANGE_PAUSED_TO_READY:
2537 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2539 switch (transition) {
2540 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2541 gst_qtdemux_reset (qtdemux, TRUE);
2552 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2554 /* counts as header data */
2555 qtdemux->header_size += length;
2557 /* only consider at least a sufficiently complete ftyp atom */
2561 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2562 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2563 GST_FOURCC_ARGS (qtdemux->major_brand));
2564 if (qtdemux->comp_brands)
2565 gst_buffer_unref (qtdemux->comp_brands);
2566 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2567 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2572 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist,
2573 GstTagList * xmptaglist)
2575 /* Strip out bogus fields */
2577 if (gst_tag_list_get_scope (taglist) == GST_TAG_SCOPE_GLOBAL) {
2578 gst_tag_list_remove_tag (xmptaglist, GST_TAG_VIDEO_CODEC);
2579 gst_tag_list_remove_tag (xmptaglist, GST_TAG_AUDIO_CODEC);
2581 gst_tag_list_remove_tag (xmptaglist, GST_TAG_CONTAINER_FORMAT);
2584 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, xmptaglist);
2586 /* prioritize native tags using _KEEP mode */
2587 gst_tag_list_insert (taglist, xmptaglist, GST_TAG_MERGE_KEEP);
2588 gst_tag_list_unref (xmptaglist);
2593 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
2601 QtDemuxStream *stream;
2602 GstStructure *structure;
2603 QtDemuxCencSampleSetInfo *ss_info = NULL;
2604 const gchar *system_id;
2605 gboolean uses_sub_sample_encryption = FALSE;
2607 if (qtdemux->n_streams == 0)
2610 stream = qtdemux->streams[0];
2612 structure = gst_caps_get_structure (stream->caps, 0);
2613 if (!gst_structure_has_name (structure, "application/x-cenc")) {
2614 GST_WARNING_OBJECT (qtdemux,
2615 "Attempting PIFF box parsing on an unencrypted stream.");
2619 gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
2620 G_TYPE_STRING, &system_id, NULL);
2621 gst_qtdemux_append_protection_system_id (qtdemux, system_id);
2623 stream->protected = TRUE;
2624 stream->protection_scheme_type = FOURCC_cenc;
2626 if (!stream->protection_scheme_info)
2627 stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
2629 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2631 if (ss_info->default_properties)
2632 gst_structure_free (ss_info->default_properties);
2634 ss_info->default_properties =
2635 gst_structure_new ("application/x-cenc",
2636 "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE, NULL);
2638 if (ss_info->crypto_info) {
2639 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
2640 g_ptr_array_free (ss_info->crypto_info, TRUE);
2641 ss_info->crypto_info = NULL;
2645 gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
2647 if (!gst_byte_reader_get_uint8 (&br, &version)) {
2648 GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
2652 if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
2653 GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
2657 if ((flags & 0x000001)) {
2658 guint32 algorithm_id = 0;
2661 gboolean is_encrypted = TRUE;
2663 if (!gst_byte_reader_get_uint24_le (&br, &algorithm_id)) {
2664 GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
2669 if (algorithm_id == 0) {
2670 is_encrypted = FALSE;
2671 } else if (algorithm_id == 1) {
2672 /* FIXME: maybe store this in properties? */
2673 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
2674 } else if (algorithm_id == 2) {
2675 /* FIXME: maybe store this in properties? */
2676 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
2679 if (!gst_byte_reader_get_uint8 (&br, &iv_size))
2682 if (!gst_byte_reader_get_data (&br, 16, &kid))
2685 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
2686 gst_buffer_fill (kid_buf, 0, kid, 16);
2687 if (ss_info->default_properties)
2688 gst_structure_free (ss_info->default_properties);
2689 ss_info->default_properties =
2690 gst_structure_new ("application/x-cenc",
2691 "iv_size", G_TYPE_UINT, iv_size,
2692 "encrypted", G_TYPE_BOOLEAN, is_encrypted,
2693 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
2694 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
2695 "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
2696 gst_buffer_unref (kid_buf);
2697 } else if ((flags & 0x000002)) {
2698 uses_sub_sample_encryption = TRUE;
2701 if (!gst_byte_reader_get_uint32_be (&br, &qtdemux->cenc_aux_sample_count)) {
2702 GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
2706 ss_info->crypto_info =
2707 g_ptr_array_new_full (qtdemux->cenc_aux_sample_count,
2708 (GDestroyNotify) qtdemux_gst_structure_free);
2710 for (i = 0; i < qtdemux->cenc_aux_sample_count; ++i) {
2711 GstStructure *properties;
2715 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
2716 if (properties == NULL) {
2717 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
2721 if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
2722 GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
2723 gst_structure_free (properties);
2726 buf = gst_buffer_new_wrapped (data, iv_size);
2727 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
2728 gst_buffer_unref (buf);
2730 if (uses_sub_sample_encryption) {
2731 guint16 n_subsamples;
2733 if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
2734 || n_subsamples == 0) {
2735 GST_ERROR_OBJECT (qtdemux,
2736 "failed to get subsample count for sample %u", i);
2737 gst_structure_free (properties);
2740 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
2741 if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
2742 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
2744 gst_structure_free (properties);
2747 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
2748 gst_structure_set (properties,
2749 "subsample_count", G_TYPE_UINT, n_subsamples,
2750 "subsamples", GST_TYPE_BUFFER, buf, NULL);
2751 gst_buffer_unref (buf);
2753 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
2756 g_ptr_array_add (ss_info->crypto_info, properties);
2761 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2763 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2764 0x97, 0xA9, 0x42, 0xE8,
2765 0x9C, 0x71, 0x99, 0x94,
2766 0x91, 0xE3, 0xAF, 0xAC
2768 static const guint8 playready_uuid[] = {
2769 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2770 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2773 static const guint8 piff_sample_encryption_uuid[] = {
2774 0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
2775 0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
2780 /* counts as header data */
2781 qtdemux->header_size += length;
2783 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2785 if (length <= offset + 16) {
2786 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2790 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2792 GstTagList *taglist;
2794 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2795 length - offset - 16, NULL);
2796 taglist = gst_tag_list_from_xmp_buffer (buf);
2797 gst_buffer_unref (buf);
2799 /* make sure we have a usable taglist */
2800 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
2802 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
2804 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
2806 const gunichar2 *s_utf16;
2809 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
2810 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
2811 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
2812 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
2816 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
2817 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
2819 } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
2820 qtdemux_parse_piff (qtdemux, buffer, length, offset);
2822 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
2823 GST_READ_UINT32_LE (buffer + offset),
2824 GST_READ_UINT32_LE (buffer + offset + 4),
2825 GST_READ_UINT32_LE (buffer + offset + 8),
2826 GST_READ_UINT32_LE (buffer + offset + 12));
2831 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2833 GstSidxParser sidx_parser;
2834 GstIsoffParserResult res;
2837 gst_isoff_qt_sidx_parser_init (&sidx_parser);
2840 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
2842 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
2843 if (res == GST_ISOFF_QT_PARSER_DONE) {
2844 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
2846 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
2849 /* caller verifies at least 8 bytes in buf */
2851 extract_initial_length_and_fourcc (const guint8 * data, guint size,
2852 guint64 * plength, guint32 * pfourcc)
2857 length = QT_UINT32 (data);
2858 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2859 fourcc = QT_FOURCC (data + 4);
2860 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
2863 length = G_MAXUINT64;
2864 } else if (length == 1 && size >= 16) {
2865 /* this means we have an extended size, which is the 64 bit value of
2866 * the next 8 bytes */
2867 length = QT_UINT64 (data + 8);
2868 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2878 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
2880 guint32 version = 0;
2881 GstClockTime duration = 0;
2883 if (!gst_byte_reader_get_uint32_be (br, &version))
2888 if (!gst_byte_reader_get_uint64_be (br, &duration))
2893 if (!gst_byte_reader_get_uint32_be (br, &dur))
2898 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
2899 qtdemux->duration = duration;
2905 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
2911 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
2912 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
2914 if (!stream->parsed_trex && qtdemux->moov_node) {
2916 GstByteReader trex_data;
2918 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
2920 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
2923 guint32 id = 0, dur = 0, size = 0, flags = 0, dummy = 0;
2925 /* skip version/flags */
2926 if (!gst_byte_reader_skip (&trex_data, 4))
2928 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
2930 if (id != stream->track_id)
2932 /* sample description index; ignore */
2933 if (!gst_byte_reader_get_uint32_be (&trex_data, &dummy))
2935 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2937 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
2939 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
2942 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
2943 "duration %d, size %d, flags 0x%x", stream->track_id,
2946 stream->parsed_trex = TRUE;
2947 stream->def_sample_duration = dur;
2948 stream->def_sample_size = size;
2949 stream->def_sample_flags = flags;
2952 /* iterate all siblings */
2953 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
2959 *ds_duration = stream->def_sample_duration;
2960 *ds_size = stream->def_sample_size;
2961 *ds_flags = stream->def_sample_flags;
2963 /* even then, above values are better than random ... */
2964 if (G_UNLIKELY (!stream->parsed_trex)) {
2965 GST_WARNING_OBJECT (qtdemux,
2966 "failed to find fragment defaults for stream %d", stream->track_id);
2973 /* This method should be called whenever a more accurate duration might
2974 * have been found. It will update all relevant variables if/where needed
2977 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
2981 GstClockTime prevdur;
2983 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
2985 if (movdur > qtdemux->duration) {
2986 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
2987 GST_DEBUG_OBJECT (qtdemux,
2988 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
2989 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
2990 qtdemux->duration = movdur;
2991 GST_DEBUG_OBJECT (qtdemux,
2992 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
2993 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
2994 GST_TIME_ARGS (qtdemux->segment.stop));
2995 if (qtdemux->segment.duration == prevdur) {
2996 /* If the current segment has duration/stop identical to previous duration
2997 * update them also (because they were set at that point in time with
2998 * the wrong duration */
2999 /* We convert the value *from* the timescale version to avoid rounding errors */
3000 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
3001 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
3002 qtdemux->segment.duration = fixeddur;
3003 qtdemux->segment.stop = fixeddur;
3006 for (i = 0; i < qtdemux->n_streams; i++) {
3007 QtDemuxStream *stream = qtdemux->streams[i];
3009 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
3010 if (movdur > stream->duration) {
3011 GST_DEBUG_OBJECT (qtdemux,
3012 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
3013 GST_TIME_ARGS (duration));
3014 stream->duration = movdur;
3015 if (stream->dummy_segment) {
3016 /* Update all dummy values to new duration */
3017 stream->segments[0].stop_time = duration;
3018 stream->segments[0].duration = duration;
3019 stream->segments[0].media_stop = duration;
3021 /* let downstream know we possibly have a new stop time */
3022 if (stream->segment_index != -1) {
3025 if (qtdemux->segment.rate >= 0) {
3026 pos = stream->segment.start;
3028 pos = stream->segment.stop;
3031 gst_qtdemux_stream_update_segment (qtdemux, stream,
3032 stream->segment_index, pos, NULL, NULL);
3041 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
3042 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
3043 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
3044 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts,
3047 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
3049 gint32 data_offset = 0;
3050 guint32 flags = 0, first_flags = 0, samples_count = 0;
3053 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
3054 QtDemuxSample *sample;
3055 gboolean ismv = FALSE;
3056 gint64 initial_offset;
3058 GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
3059 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
3060 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
3061 d_sample_size, d_sample_flags, *base_offset, decode_ts);
3063 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
3064 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
3068 /* presence of stss or not can't really tell us much,
3069 * and flags and so on tend to be marginally reliable in these files */
3070 if (stream->subtype == FOURCC_soun) {
3071 GST_DEBUG_OBJECT (qtdemux,
3072 "sound track in fragmented file; marking all keyframes");
3073 stream->all_keyframe = TRUE;
3076 if (!gst_byte_reader_skip (trun, 1) ||
3077 !gst_byte_reader_get_uint24_be (trun, &flags))
3080 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3083 if (flags & TR_DATA_OFFSET) {
3084 /* note this is really signed */
3085 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3087 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3088 /* default base offset = first byte of moof */
3089 if (*base_offset == -1) {
3090 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3091 *base_offset = moof_offset;
3093 *running_offset = *base_offset + data_offset;
3095 /* if no offset at all, that would mean data starts at moof start,
3096 * which is a bit wrong and is ismv crappy way, so compensate
3097 * assuming data is in mdat following moof */
3098 if (*base_offset == -1) {
3099 *base_offset = moof_offset + moof_length + 8;
3100 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3103 if (*running_offset == -1)
3104 *running_offset = *base_offset;
3107 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3109 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3110 data_offset, flags, samples_count);
3112 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3113 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3114 GST_DEBUG_OBJECT (qtdemux,
3115 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3116 flags ^= TR_FIRST_SAMPLE_FLAGS;
3118 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3120 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3124 /* FIXME ? spec says other bits should also be checked to determine
3125 * entry size (and prefix size for that matter) */
3127 dur_offset = size_offset = 0;
3128 if (flags & TR_SAMPLE_DURATION) {
3129 GST_LOG_OBJECT (qtdemux, "entry duration present");
3130 dur_offset = entry_size;
3133 if (flags & TR_SAMPLE_SIZE) {
3134 GST_LOG_OBJECT (qtdemux, "entry size present");
3135 size_offset = entry_size;
3138 if (flags & TR_SAMPLE_FLAGS) {
3139 GST_LOG_OBJECT (qtdemux, "entry flags present");
3140 flags_offset = entry_size;
3143 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3144 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3145 ct_offset = entry_size;
3149 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3151 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3153 if (stream->n_samples + samples_count >=
3154 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3157 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3158 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3159 (stream->n_samples + samples_count) *
3160 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3162 /* create a new array of samples if it's the first sample parsed */
3163 if (stream->n_samples == 0) {
3164 g_assert (stream->samples == NULL);
3165 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3166 /* or try to reallocate it with space enough to insert the new samples */
3168 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3169 stream->n_samples + samples_count);
3170 if (stream->samples == NULL)
3173 if (qtdemux->fragment_start != -1) {
3174 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3175 qtdemux->fragment_start = -1;
3177 if (stream->n_samples == 0) {
3178 if (decode_ts > 0) {
3179 timestamp = decode_ts;
3180 } else if (stream->pending_seek != NULL) {
3181 /* if we don't have a timestamp from a tfdt box, we'll use the one
3182 * from the mfra seek table */
3183 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3184 GST_TIME_ARGS (stream->pending_seek->ts));
3186 /* FIXME: this is not fully correct, the timestamp refers to the random
3187 * access sample refered to in the tfra entry, which may not necessarily
3188 * be the first sample in the tfrag/trun (but hopefully/usually is) */
3189 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3194 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3195 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3196 GST_TIME_ARGS (gst_ts));
3198 /* subsequent fragments extend stream */
3200 stream->samples[stream->n_samples - 1].timestamp +
3201 stream->samples[stream->n_samples - 1].duration;
3203 /* If this is a GST_FORMAT_BYTES stream and there's a significant
3204 * difference (1 sec.) between decode_ts and timestamp, prefer the
3206 if (has_tfdt && !qtdemux->upstream_format_is_time
3207 && ABSDIFF (decode_ts, timestamp) >
3208 MAX (stream->duration_last_moof / 2,
3209 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) {
3210 GST_INFO_OBJECT (qtdemux,
3211 "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT
3212 ") are significantly different (more than %" GST_TIME_FORMAT
3213 "), using decode_ts",
3214 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)),
3215 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)),
3216 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
3217 MAX (stream->duration_last_moof / 2,
3218 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND)))));
3219 timestamp = decode_ts;
3222 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3223 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3224 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3228 initial_offset = *running_offset;
3230 sample = stream->samples + stream->n_samples;
3231 for (i = 0; i < samples_count; i++) {
3232 guint32 dur, size, sflags, ct;
3234 /* first read sample data */
3235 if (flags & TR_SAMPLE_DURATION) {
3236 dur = QT_UINT32 (data + dur_offset);
3238 dur = d_sample_duration;
3240 if (flags & TR_SAMPLE_SIZE) {
3241 size = QT_UINT32 (data + size_offset);
3243 size = d_sample_size;
3245 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3247 sflags = first_flags;
3249 sflags = d_sample_flags;
3251 } else if (flags & TR_SAMPLE_FLAGS) {
3252 sflags = QT_UINT32 (data + flags_offset);
3254 sflags = d_sample_flags;
3256 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3257 ct = QT_UINT32 (data + ct_offset);
3263 /* fill the sample information */
3264 sample->offset = *running_offset;
3265 sample->pts_offset = ct;
3266 sample->size = size;
3267 sample->timestamp = timestamp;
3268 sample->duration = dur;
3269 /* sample-is-difference-sample */
3270 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3271 * now idea how it relates to bitfield other than massive LE/BE confusion */
3272 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3273 *running_offset += size;
3275 stream->duration_moof += dur;
3279 /* Update total duration if needed */
3280 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3282 /* Pre-emptively figure out size of mdat based on trun information.
3283 * If the [mdat] atom is effectivelly read, it will be replaced by the actual
3284 * size, else we will still be able to use this when dealing with gap'ed
3286 qtdemux->mdatleft = *running_offset - initial_offset;
3287 qtdemux->mdatoffset = initial_offset;
3288 qtdemux->mdatsize = qtdemux->mdatleft;
3290 stream->n_samples += samples_count;
3291 stream->n_samples_moof += samples_count;
3293 if (stream->pending_seek != NULL)
3294 stream->pending_seek = NULL;
3300 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3305 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3311 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3312 "be larger than %uMB (broken file?)", stream->n_samples,
3313 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3318 /* find stream with @id */
3319 static inline QtDemuxStream *
3320 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3322 QtDemuxStream *stream;
3326 if (G_UNLIKELY (!id)) {
3327 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3331 /* try to get it fast and simple */
3332 if (G_LIKELY (id <= qtdemux->n_streams)) {
3333 stream = qtdemux->streams[id - 1];
3334 if (G_LIKELY (stream->track_id == id))
3338 /* linear search otherwise */
3339 for (i = 0; i < qtdemux->n_streams; i++) {
3340 stream = qtdemux->streams[i];
3341 if (stream->track_id == id)
3344 if (qtdemux->mss_mode) {
3345 /* mss should have only 1 stream anyway */
3346 return qtdemux->streams[0];
3353 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3354 guint32 * fragment_number)
3356 if (!gst_byte_reader_skip (mfhd, 4))
3358 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3363 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3369 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3370 QtDemuxStream ** stream, guint32 * default_sample_duration,
3371 guint32 * default_sample_size, guint32 * default_sample_flags,
3372 gint64 * base_offset)
3375 guint32 track_id = 0;
3377 if (!gst_byte_reader_skip (tfhd, 1) ||
3378 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3381 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3384 *stream = qtdemux_find_stream (qtdemux, track_id);
3385 if (G_UNLIKELY (!*stream))
3386 goto unknown_stream;
3388 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3389 *base_offset = qtdemux->moof_offset;
3391 if (flags & TF_BASE_DATA_OFFSET)
3392 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3395 /* obtain stream defaults */
3396 qtdemux_parse_trex (qtdemux, *stream,
3397 default_sample_duration, default_sample_size, default_sample_flags);
3399 /* FIXME: Handle TF_SAMPLE_DESCRIPTION_INDEX properly */
3400 if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
3401 if (!gst_byte_reader_skip (tfhd, 4))
3404 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3405 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3408 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3409 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3412 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3413 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3420 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3425 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
3431 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3432 guint64 * decode_time)
3434 guint32 version = 0;
3436 if (!gst_byte_reader_get_uint32_be (br, &version))
3441 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3444 guint32 dec_time = 0;
3445 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3447 *decode_time = dec_time;
3450 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3457 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3462 /* Returns a pointer to a GstStructure containing the properties of
3463 * the stream sample identified by @sample_index. The caller must unref
3464 * the returned object after use. Returns NULL if unsuccessful. */
3465 static GstStructure *
3466 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3467 QtDemuxStream * stream, guint sample_index)
3469 QtDemuxCencSampleSetInfo *info = NULL;
3471 g_return_val_if_fail (stream != NULL, NULL);
3472 g_return_val_if_fail (stream->protected, NULL);
3473 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3475 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3477 /* Currently, cenc properties for groups of samples are not supported, so
3478 * simply return a copy of the default sample properties */
3479 return gst_structure_copy (info->default_properties);
3482 /* Parses the sizes of sample auxiliary information contained within a stream,
3483 * as given in a saiz box. Returns array of sample_count guint8 size values,
3484 * or NULL on failure */
3486 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3487 GstByteReader * br, guint32 * sample_count)
3491 guint8 default_info_size;
3493 g_return_val_if_fail (qtdemux != NULL, NULL);
3494 g_return_val_if_fail (stream != NULL, NULL);
3495 g_return_val_if_fail (br != NULL, NULL);
3496 g_return_val_if_fail (sample_count != NULL, NULL);
3498 if (!gst_byte_reader_get_uint32_be (br, &flags))
3502 /* aux_info_type and aux_info_type_parameter are ignored */
3503 if (!gst_byte_reader_skip (br, 8))
3507 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3509 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3511 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3513 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3516 if (default_info_size == 0) {
3517 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3521 info_sizes = g_new (guint8, *sample_count);
3522 memset (info_sizes, default_info_size, *sample_count);
3528 /* Parses the offset of sample auxiliary information contained within a stream,
3529 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3531 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3532 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3537 guint32 aux_info_type = 0;
3538 guint32 aux_info_type_parameter = 0;
3539 guint32 entry_count;
3542 const guint8 *aux_info_type_data = NULL;
3544 g_return_val_if_fail (qtdemux != NULL, FALSE);
3545 g_return_val_if_fail (stream != NULL, FALSE);
3546 g_return_val_if_fail (br != NULL, FALSE);
3547 g_return_val_if_fail (offset != NULL, FALSE);
3549 if (!gst_byte_reader_get_uint8 (br, &version))
3552 if (!gst_byte_reader_get_uint24_be (br, &flags))
3557 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3559 aux_info_type = QT_FOURCC (aux_info_type_data);
3561 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3563 } else if (stream->protected) {
3564 aux_info_type = stream->protection_scheme_type;
3566 aux_info_type = stream->fourcc;
3570 *info_type = aux_info_type;
3571 if (info_type_parameter)
3572 *info_type_parameter = aux_info_type_parameter;
3574 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3575 "aux_info_type_parameter: %#06x",
3576 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3578 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3581 if (entry_count != 1) {
3582 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3587 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3589 *offset = (guint64) off_32;
3591 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3596 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3601 qtdemux_gst_structure_free (GstStructure * gststructure)
3604 gst_structure_free (gststructure);
3608 /* Parses auxiliary information relating to samples protected using Common
3609 * Encryption (cenc); the format of this information is defined in
3610 * ISO/IEC 23001-7. Returns TRUE if successful; FALSE otherwise. */
3612 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3613 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3615 QtDemuxCencSampleSetInfo *ss_info = NULL;
3618 GPtrArray *old_crypto_info = NULL;
3619 guint old_entries = 0;
3621 g_return_val_if_fail (qtdemux != NULL, FALSE);
3622 g_return_val_if_fail (stream != NULL, FALSE);
3623 g_return_val_if_fail (br != NULL, FALSE);
3624 g_return_val_if_fail (stream->protected, FALSE);
3625 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3627 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3629 if (ss_info->crypto_info) {
3630 old_crypto_info = ss_info->crypto_info;
3631 /* Count number of non-null entries remaining at the tail end */
3632 for (i = old_crypto_info->len - 1; i >= 0; i--) {
3633 if (g_ptr_array_index (old_crypto_info, i) == NULL)
3639 ss_info->crypto_info =
3640 g_ptr_array_new_full (sample_count + old_entries,
3641 (GDestroyNotify) qtdemux_gst_structure_free);
3643 /* We preserve old entries because we parse the next moof in advance
3644 * of consuming all samples from the previous moof, and otherwise
3645 * we'd discard the corresponding crypto info for the samples
3646 * from the previous fragment. */
3648 GST_DEBUG_OBJECT (qtdemux, "Preserving %d old crypto info entries",
3650 for (i = old_crypto_info->len - old_entries; i < old_crypto_info->len; i++) {
3651 g_ptr_array_add (ss_info->crypto_info, g_ptr_array_index (old_crypto_info,
3653 g_ptr_array_index (old_crypto_info, i) = NULL;
3657 if (old_crypto_info) {
3658 /* Everything now belongs to the new array */
3659 g_ptr_array_free (old_crypto_info, TRUE);
3662 for (i = 0; i < sample_count; ++i) {
3663 GstStructure *properties;
3664 guint16 n_subsamples = 0;
3669 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3670 if (properties == NULL) {
3671 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3674 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3675 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3676 gst_structure_free (properties);
3679 if (!gst_byte_reader_dup_data (br, iv_size, &data)) {
3680 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3681 gst_structure_free (properties);
3684 buf = gst_buffer_new_wrapped (data, iv_size);
3685 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3686 gst_buffer_unref (buf);
3687 size = info_sizes[i];
3688 if (size > iv_size) {
3689 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3690 || !(n_subsamples > 0)) {
3691 gst_structure_free (properties);
3692 GST_ERROR_OBJECT (qtdemux,
3693 "failed to get subsample count for sample %u", i);
3696 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3697 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3698 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3700 gst_structure_free (properties);
3703 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3705 gst_structure_free (properties);
3708 gst_structure_set (properties,
3709 "subsample_count", G_TYPE_UINT, n_subsamples,
3710 "subsamples", GST_TYPE_BUFFER, buf, NULL);
3711 gst_buffer_unref (buf);
3713 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3715 g_ptr_array_add (ss_info->crypto_info, properties);
3720 /* Converts a UUID in raw byte form to a string representation, as defined in
3721 * RFC 4122. The caller takes ownership of the returned string and is
3722 * responsible for freeing it after use. */
3724 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3726 const guint8 *uuid = (const guint8 *) uuid_bytes;
3728 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3729 "%02x%02x-%02x%02x%02x%02x%02x%02x",
3730 uuid[0], uuid[1], uuid[2], uuid[3],
3731 uuid[4], uuid[5], uuid[6], uuid[7],
3732 uuid[8], uuid[9], uuid[10], uuid[11],
3733 uuid[12], uuid[13], uuid[14], uuid[15]);
3736 /* Parses a Protection System Specific Header box (pssh), as defined in the
3737 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3738 * information needed by a specific content protection system in order to
3739 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3742 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
3744 gchar *sysid_string;
3745 guint32 pssh_size = QT_UINT32 (node->data);
3746 GstBuffer *pssh = NULL;
3747 GstEvent *event = NULL;
3748 guint32 parent_box_type;
3751 if (G_UNLIKELY (pssh_size < 32U)) {
3752 GST_ERROR_OBJECT (qtdemux, "invalid box size");
3757 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
3759 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
3761 pssh = gst_buffer_new_wrapped (g_memdup (node->data, pssh_size), pssh_size);
3762 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
3763 gst_buffer_get_size (pssh));
3765 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
3767 /* Push an event containing the pssh box onto the queues of all streams. */
3768 event = gst_event_new_protection (sysid_string, pssh,
3769 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
3770 for (i = 0; i < qtdemux->n_streams; ++i) {
3771 g_queue_push_tail (&qtdemux->streams[i]->protection_scheme_event_queue,
3772 gst_event_ref (event));
3774 g_free (sysid_string);
3775 gst_event_unref (event);
3776 gst_buffer_unref (pssh);
3781 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
3782 guint64 moof_offset, QtDemuxStream * stream)
3784 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
3786 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
3787 GNode *saiz_node, *saio_node, *pssh_node;
3788 GstByteReader saiz_data, saio_data;
3789 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
3790 gint64 base_offset, running_offset;
3793 /* NOTE @stream ignored */
3795 moof_node = g_node_new ((guint8 *) buffer);
3796 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
3797 qtdemux_node_dump (qtdemux, moof_node);
3799 /* Get fragment number from mfhd and check it's valid */
3801 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
3802 if (mfhd_node == NULL)
3804 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
3806 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
3808 /* unknown base_offset to start with */
3809 base_offset = running_offset = -1;
3810 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
3812 guint64 decode_time = 0;
3814 /* Fragment Header node */
3816 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
3820 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
3821 &ds_size, &ds_flags, &base_offset))
3824 /* The following code assumes at most a single set of sample auxiliary
3825 * data in the fragment (consisting of a saiz box and a corresponding saio
3826 * box); in theory, however, there could be multiple sets of sample
3827 * auxiliary data in a fragment. */
3829 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
3832 guint32 info_type = 0;
3834 guint32 info_type_parameter = 0;
3836 g_free (qtdemux->cenc_aux_info_sizes);
3838 qtdemux->cenc_aux_info_sizes =
3839 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
3840 &qtdemux->cenc_aux_sample_count);
3841 if (qtdemux->cenc_aux_info_sizes == NULL) {
3842 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
3846 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
3849 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
3850 g_free (qtdemux->cenc_aux_info_sizes);
3851 qtdemux->cenc_aux_info_sizes = NULL;
3855 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
3856 &info_type, &info_type_parameter, &offset))) {
3857 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
3858 g_free (qtdemux->cenc_aux_info_sizes);
3859 qtdemux->cenc_aux_info_sizes = NULL;
3862 if (base_offset > -1 && base_offset > qtdemux->moof_offset)
3863 offset += (guint64) (base_offset - qtdemux->moof_offset);
3864 if (info_type == FOURCC_cenc && info_type_parameter == 0U) {
3866 if (offset > length) {
3867 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
3868 qtdemux->cenc_aux_info_offset = offset;
3870 gst_byte_reader_init (&br, buffer + offset, length - offset);
3871 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
3872 qtdemux->cenc_aux_info_sizes,
3873 qtdemux->cenc_aux_sample_count)) {
3874 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
3875 g_free (qtdemux->cenc_aux_info_sizes);
3876 qtdemux->cenc_aux_info_sizes = NULL;
3884 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
3887 /* We'll use decode_time to interpolate timestamps
3888 * in case the input timestamps are missing */
3889 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
3891 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
3892 " (%" GST_TIME_FORMAT ")", decode_time,
3893 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_time)));
3895 /* Discard the fragment buffer timestamp info to avoid using it.
3896 * Rely on tfdt instead as it is more accurate than the timestamp
3897 * that is fetched from a manifest/playlist and is usually
3899 qtdemux->fragment_start = -1;
3902 if (G_UNLIKELY (!stream)) {
3903 /* we lost track of offset, we'll need to regain it,
3904 * but can delay complaining until later or avoid doing so altogether */
3908 if (G_UNLIKELY (base_offset < -1))
3911 if (qtdemux->upstream_format_is_time)
3912 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
3914 /* initialise moof sample data */
3915 stream->n_samples_moof = 0;
3916 stream->duration_last_moof = stream->duration_moof;
3917 stream->duration_moof = 0;
3919 /* Track Run node */
3921 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
3924 qtdemux_parse_trun (qtdemux, &trun_data, stream,
3925 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
3926 &running_offset, decode_time, (tfdt_node != NULL));
3927 /* iterate all siblings */
3928 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
3932 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
3934 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
3935 guint32 box_length = QT_UINT32 (uuid_buffer);
3937 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
3940 /* if no new base_offset provided for next traf,
3941 * base is end of current traf */
3942 base_offset = running_offset;
3943 running_offset = -1;
3945 if (stream->n_samples_moof && stream->duration_moof)
3946 stream->new_caps = TRUE;
3949 /* iterate all siblings */
3950 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
3953 /* parse any protection system info */
3954 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
3956 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
3957 qtdemux_parse_pssh (qtdemux, pssh_node);
3958 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
3961 g_node_destroy (moof_node);
3966 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
3971 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
3976 GST_DEBUG_OBJECT (qtdemux, "lost offset");
3981 g_node_destroy (moof_node);
3982 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
3983 (_("This file is corrupt and cannot be played.")), (NULL));
3989 /* might be used if some day we actually use mfra & co
3990 * for random access to fragments,
3991 * but that will require quite some modifications and much less relying
3992 * on a sample array */
3996 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
3998 QtDemuxStream *stream;
3999 guint32 ver_flags, track_id, len, num_entries, i;
4000 guint value_size, traf_size, trun_size, sample_size;
4001 guint64 time = 0, moof_offset = 0;
4003 GstBuffer *buf = NULL;
4008 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
4010 if (!gst_byte_reader_skip (&tfra, 8))
4013 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
4016 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
4017 || !gst_byte_reader_get_uint32_be (&tfra, &len)
4018 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
4021 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
4023 stream = qtdemux_find_stream (qtdemux, track_id);
4025 goto unknown_trackid;
4027 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
4028 sample_size = (len & 3) + 1;
4029 trun_size = ((len & 12) >> 2) + 1;
4030 traf_size = ((len & 48) >> 4) + 1;
4032 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
4033 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
4035 if (num_entries == 0)
4038 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
4039 value_size + value_size + traf_size + trun_size + sample_size))
4042 g_free (stream->ra_entries);
4043 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
4044 stream->n_ra_entries = num_entries;
4046 for (i = 0; i < num_entries; i++) {
4047 qt_atom_parser_get_offset (&tfra, value_size, &time);
4048 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
4049 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
4050 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
4051 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
4053 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
4055 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
4056 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
4058 stream->ra_entries[i].ts = time;
4059 stream->ra_entries[i].moof_offset = moof_offset;
4061 /* don't want to go through the entire file and read all moofs at startup */
4063 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
4064 if (ret != GST_FLOW_OK)
4066 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
4067 moof_offset, stream);
4068 gst_buffer_unref (buf);
4072 check_update_duration (qtdemux, time);
4079 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
4084 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
4089 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4095 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
4097 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
4098 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
4099 GstBuffer *mfro = NULL, *mfra = NULL;
4101 gboolean ret = FALSE;
4102 GNode *mfra_node, *tfra_node;
4103 guint64 mfra_offset = 0;
4104 guint32 fourcc, mfra_size;
4107 /* query upstream size in bytes */
4108 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4109 goto size_query_failed;
4111 /* mfro box should be at the very end of the file */
4112 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4113 if (flow != GST_FLOW_OK)
4116 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4118 fourcc = QT_FOURCC (mfro_map.data + 4);
4119 if (fourcc != FOURCC_mfro)
4122 GST_INFO_OBJECT (qtdemux, "Found mfro box");
4123 if (mfro_map.size < 16)
4124 goto invalid_mfro_size;
4126 mfra_size = QT_UINT32 (mfro_map.data + 12);
4127 if (mfra_size >= len)
4128 goto invalid_mfra_size;
4130 mfra_offset = len - mfra_size;
4132 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4133 mfra_offset, mfra_size);
4135 /* now get and parse mfra box */
4136 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4137 if (flow != GST_FLOW_OK)
4140 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4142 mfra_node = g_node_new ((guint8 *) mfra_map.data);
4143 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4145 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4148 qtdemux_parse_tfra (qtdemux, tfra_node);
4149 /* iterate all siblings */
4150 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4152 g_node_destroy (mfra_node);
4154 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4160 if (mfro_map.memory != NULL)
4161 gst_buffer_unmap (mfro, &mfro_map);
4162 gst_buffer_unref (mfro);
4165 if (mfra_map.memory != NULL)
4166 gst_buffer_unmap (mfra, &mfra_map);
4167 gst_buffer_unref (mfra);
4174 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4179 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4184 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4189 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4195 add_offset (guint64 offset, guint64 advance)
4197 /* Avoid 64-bit overflow by clamping */
4198 if (offset > G_MAXUINT64 - advance)
4200 return offset + advance;
4203 static GstFlowReturn
4204 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4208 GstBuffer *buf = NULL;
4209 GstFlowReturn ret = GST_FLOW_OK;
4210 guint64 cur_offset = qtdemux->offset;
4213 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4214 if (G_UNLIKELY (ret != GST_FLOW_OK))
4216 gst_buffer_map (buf, &map, GST_MAP_READ);
4217 if (G_LIKELY (map.size >= 8))
4218 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4219 gst_buffer_unmap (buf, &map);
4220 gst_buffer_unref (buf);
4222 /* maybe we already got most we needed, so only consider this eof */
4223 if (G_UNLIKELY (length == 0)) {
4224 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4225 (_("Invalid atom size.")),
4226 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4227 GST_FOURCC_ARGS (fourcc)));
4234 /* record for later parsing when needed */
4235 if (!qtdemux->moof_offset) {
4236 qtdemux->moof_offset = qtdemux->offset;
4238 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4241 qtdemux->offset += length; /* skip moof and keep going */
4243 if (qtdemux->got_moov) {
4244 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4255 GST_LOG_OBJECT (qtdemux,
4256 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4257 GST_FOURCC_ARGS (fourcc), cur_offset);
4258 qtdemux->offset = add_offset (qtdemux->offset, length);
4263 GstBuffer *moov = NULL;
4265 if (qtdemux->got_moov) {
4266 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4267 qtdemux->offset = add_offset (qtdemux->offset, length);
4271 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4272 if (ret != GST_FLOW_OK)
4274 gst_buffer_map (moov, &map, GST_MAP_READ);
4276 if (length != map.size) {
4277 /* Some files have a 'moov' atom at the end of the file which contains
4278 * a terminal 'free' atom where the body of the atom is missing.
4279 * Check for, and permit, this special case.
4281 if (map.size >= 8) {
4282 guint8 *final_data = map.data + (map.size - 8);
4283 guint32 final_length = QT_UINT32 (final_data);
4284 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4286 if (final_fourcc == FOURCC_free
4287 && map.size + final_length - 8 == length) {
4288 /* Ok, we've found that special case. Allocate a new buffer with
4289 * that free atom actually present. */
4290 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4291 gst_buffer_fill (newmoov, 0, map.data, map.size);
4292 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4293 gst_buffer_unmap (moov, &map);
4294 gst_buffer_unref (moov);
4296 gst_buffer_map (moov, &map, GST_MAP_READ);
4301 if (length != map.size) {
4302 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4303 (_("This file is incomplete and cannot be played.")),
4304 ("We got less than expected (received %" G_GSIZE_FORMAT
4305 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4306 (guint) length, cur_offset));
4307 gst_buffer_unmap (moov, &map);
4308 gst_buffer_unref (moov);
4309 ret = GST_FLOW_ERROR;
4312 qtdemux->offset += length;
4314 qtdemux_parse_moov (qtdemux, map.data, length);
4315 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4317 qtdemux_parse_tree (qtdemux);
4318 if (qtdemux->moov_node_compressed) {
4319 g_node_destroy (qtdemux->moov_node_compressed);
4320 g_free (qtdemux->moov_node->data);
4322 qtdemux->moov_node_compressed = NULL;
4323 g_node_destroy (qtdemux->moov_node);
4324 qtdemux->moov_node = NULL;
4325 gst_buffer_unmap (moov, &map);
4326 gst_buffer_unref (moov);
4327 qtdemux->got_moov = TRUE;
4333 GstBuffer *ftyp = NULL;
4335 /* extract major brand; might come in handy for ISO vs QT issues */
4336 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4337 if (ret != GST_FLOW_OK)
4339 qtdemux->offset += length;
4340 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4341 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4342 gst_buffer_unmap (ftyp, &map);
4343 gst_buffer_unref (ftyp);
4348 GstBuffer *uuid = NULL;
4350 /* uuid are extension atoms */
4351 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4352 if (ret != GST_FLOW_OK)
4354 qtdemux->offset += length;
4355 gst_buffer_map (uuid, &map, GST_MAP_READ);
4356 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4357 gst_buffer_unmap (uuid, &map);
4358 gst_buffer_unref (uuid);
4363 GstBuffer *sidx = NULL;
4364 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4365 if (ret != GST_FLOW_OK)
4367 qtdemux->offset += length;
4368 gst_buffer_map (sidx, &map, GST_MAP_READ);
4369 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4370 gst_buffer_unmap (sidx, &map);
4371 gst_buffer_unref (sidx);
4376 GstBuffer *unknown = NULL;
4378 GST_LOG_OBJECT (qtdemux,
4379 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4380 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4382 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4383 if (ret != GST_FLOW_OK)
4385 gst_buffer_map (unknown, &map, GST_MAP_READ);
4386 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4387 gst_buffer_unmap (unknown, &map);
4388 gst_buffer_unref (unknown);
4389 qtdemux->offset += length;
4395 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4396 /* digested all data, show what we have */
4397 qtdemux_prepare_streams (qtdemux);
4398 ret = qtdemux_expose_streams (qtdemux);
4400 qtdemux->state = QTDEMUX_STATE_MOVIE;
4401 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4408 /* Seeks to the previous keyframe of the indexed stream and
4409 * aligns other streams with respect to the keyframe timestamp
4410 * of indexed stream. Only called in case of Reverse Playback
4412 static GstFlowReturn
4413 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4416 guint32 seg_idx = 0, k_index = 0;
4417 guint32 ref_seg_idx, ref_k_index;
4418 GstClockTime k_pos = 0, last_stop = 0;
4419 QtDemuxSegment *seg = NULL;
4420 QtDemuxStream *ref_str = NULL;
4421 guint64 seg_media_start_mov; /* segment media start time in mov format */
4424 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4425 * and finally align all the other streams on that timestamp with their
4426 * respective keyframes */
4427 for (n = 0; n < qtdemux->n_streams; n++) {
4428 QtDemuxStream *str = qtdemux->streams[n];
4430 /* No candidate yet, take the first stream */
4436 /* So that stream has a segment, we prefer video streams */
4437 if (str->subtype == FOURCC_vide) {
4443 if (G_UNLIKELY (!ref_str)) {
4444 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4448 if (G_UNLIKELY (!ref_str->from_sample)) {
4449 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4453 /* So that stream has been playing from from_sample to to_sample. We will
4454 * get the timestamp of the previous sample and search for a keyframe before
4455 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4456 if (ref_str->subtype == FOURCC_vide) {
4457 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4458 ref_str->from_sample - 1, FALSE);
4460 if (ref_str->from_sample >= 10)
4461 k_index = ref_str->from_sample - 10;
4467 ref_str->samples[k_index].timestamp +
4468 ref_str->samples[k_index].pts_offset;
4470 /* get current segment for that stream */
4471 seg = &ref_str->segments[ref_str->segment_index];
4472 /* Use segment start in original timescale for comparisons */
4473 seg_media_start_mov = seg->trak_media_start;
4475 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4476 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT "\n",
4477 k_index, target_ts, seg_media_start_mov,
4478 GST_TIME_ARGS (seg->media_start));
4480 /* Crawl back through segments to find the one containing this I frame */
4481 while (target_ts < seg_media_start_mov) {
4482 GST_DEBUG_OBJECT (qtdemux,
4483 "keyframe position (sample %u) is out of segment %u " " target %"
4484 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4485 ref_str->segment_index, target_ts, seg_media_start_mov);
4487 if (G_UNLIKELY (!ref_str->segment_index)) {
4488 /* Reached first segment, let's consider it's EOS */
4491 ref_str->segment_index--;
4492 seg = &ref_str->segments[ref_str->segment_index];
4493 /* Use segment start in original timescale for comparisons */
4494 seg_media_start_mov = seg->trak_media_start;
4496 /* Calculate time position of the keyframe and where we should stop */
4498 QTSTREAMTIME_TO_GSTTIME (ref_str,
4499 target_ts - seg->trak_media_start) + seg->time;
4501 QTSTREAMTIME_TO_GSTTIME (ref_str,
4502 ref_str->samples[ref_str->from_sample].timestamp -
4503 seg->trak_media_start) + seg->time;
4505 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4506 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4507 k_index, GST_TIME_ARGS (k_pos));
4509 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4510 qtdemux->segment.position = last_stop;
4511 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4512 GST_TIME_ARGS (last_stop));
4514 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4515 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4519 ref_seg_idx = ref_str->segment_index;
4520 ref_k_index = k_index;
4522 /* Align them all on this */
4523 for (n = 0; n < qtdemux->n_streams; n++) {
4525 GstClockTime seg_time = 0;
4526 QtDemuxStream *str = qtdemux->streams[n];
4528 /* aligning reference stream again might lead to backing up to yet another
4529 * keyframe (due to timestamp rounding issues),
4530 * potentially putting more load on downstream; so let's try to avoid */
4531 if (str == ref_str) {
4532 seg_idx = ref_seg_idx;
4533 seg = &str->segments[seg_idx];
4534 k_index = ref_k_index;
4535 GST_DEBUG_OBJECT (qtdemux, "reference stream %d segment %d, "
4536 "sample at index %d", n, ref_str->segment_index, k_index);
4538 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4539 GST_DEBUG_OBJECT (qtdemux,
4540 "stream %d align segment %d for keyframe pos %" GST_TIME_FORMAT, n,
4541 seg_idx, GST_TIME_ARGS (k_pos));
4543 /* get segment and time in the segment */
4544 seg = &str->segments[seg_idx];
4545 seg_time = k_pos - seg->time;
4547 /* get the media time in the segment.
4548 * No adjustment for empty "filler" segments */
4549 if (seg->media_start != GST_CLOCK_TIME_NONE)
4550 seg_time += seg->media_start;
4552 /* get the index of the sample with media time */
4553 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4554 GST_DEBUG_OBJECT (qtdemux,
4555 "stream %d sample for %" GST_TIME_FORMAT " at %u", n,
4556 GST_TIME_ARGS (seg_time), index);
4558 /* find previous keyframe */
4559 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
4562 /* Remember until where we want to go */
4563 str->to_sample = str->from_sample - 1;
4564 /* Define our time position */
4566 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4567 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4568 if (seg->media_start != GST_CLOCK_TIME_NONE)
4569 str->time_position -= seg->media_start;
4571 /* Now seek back in time */
4572 gst_qtdemux_move_stream (qtdemux, str, k_index);
4573 GST_DEBUG_OBJECT (qtdemux, "stream %d keyframe at %u, time position %"
4574 GST_TIME_FORMAT " playing from sample %u to %u", n, k_index,
4575 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4581 return GST_FLOW_EOS;
4585 * Gets the current qt segment start, stop and position for the
4586 * given time offset. This is used in update_segment()
4589 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
4590 QtDemuxStream * stream, GstClockTime offset,
4591 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
4593 GstClockTime seg_time;
4594 GstClockTime start, stop, time;
4595 QtDemuxSegment *segment;
4597 segment = &stream->segments[stream->segment_index];
4599 /* get time in this segment */
4600 seg_time = (offset - segment->time) * segment->rate;
4602 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4603 GST_TIME_ARGS (seg_time));
4605 if (G_UNLIKELY (seg_time > segment->duration)) {
4606 GST_LOG_OBJECT (stream->pad,
4607 "seg_time > segment->duration %" GST_TIME_FORMAT,
4608 GST_TIME_ARGS (segment->duration));
4609 seg_time = segment->duration;
4612 /* qtdemux->segment.stop is in outside-time-realm, whereas
4613 * segment->media_stop is in track-time-realm.
4615 * In order to compare the two, we need to bring segment.stop
4616 * into the track-time-realm
4618 * FIXME - does this comment still hold? Don't see any conversion here */
4620 stop = qtdemux->segment.stop;
4621 if (stop == GST_CLOCK_TIME_NONE)
4622 stop = qtdemux->segment.duration;
4623 if (stop == GST_CLOCK_TIME_NONE)
4624 stop = segment->media_stop;
4627 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4629 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4630 start = segment->time + seg_time;
4632 stop = start - seg_time + segment->duration;
4633 } else if (qtdemux->segment.rate >= 0) {
4634 start = MIN (segment->media_start + seg_time, stop);
4637 if (segment->media_start >= qtdemux->segment.start) {
4638 time = segment->time;
4640 time = segment->time + (qtdemux->segment.start - segment->media_start);
4643 start = MAX (segment->media_start, qtdemux->segment.start);
4644 stop = MIN (segment->media_start + seg_time, stop);
4653 * Updates the qt segment used for the stream and pushes a new segment event
4654 * downstream on this stream's pad.
4657 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4658 gint seg_idx, GstClockTime offset, GstClockTime * _start,
4659 GstClockTime * _stop)
4661 QtDemuxSegment *segment;
4662 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
4666 /* update the current segment */
4667 stream->segment_index = seg_idx;
4669 /* get the segment */
4670 segment = &stream->segments[seg_idx];
4672 if (G_UNLIKELY (offset < segment->time)) {
4673 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4674 GST_TIME_ARGS (segment->time));
4678 /* segment lies beyond total indicated duration */
4679 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4680 segment->time > qtdemux->segment.duration)) {
4681 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4682 " < segment->time %" GST_TIME_FORMAT,
4683 GST_TIME_ARGS (qtdemux->segment.duration),
4684 GST_TIME_ARGS (segment->time));
4688 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
4689 &start, &stop, &time);
4691 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
4692 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
4693 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
4695 /* combine global rate with that of the segment */
4696 rate = segment->rate * qtdemux->segment.rate;
4698 /* Copy flags from main segment */
4699 stream->segment.flags = qtdemux->segment.flags;
4701 /* update the segment values used for clipping */
4702 stream->segment.offset = qtdemux->segment.offset;
4703 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
4704 stream->segment.applied_rate = qtdemux->segment.applied_rate;
4705 stream->segment.rate = rate;
4706 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
4707 stream->cslg_shift);
4708 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
4709 stream->cslg_shift);
4710 stream->segment.time = time;
4711 stream->segment.position = stream->segment.start;
4713 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
4716 /* now prepare and send the segment */
4718 event = gst_event_new_segment (&stream->segment);
4719 if (qtdemux->segment_seqnum) {
4720 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
4722 gst_pad_push_event (stream->pad, event);
4723 /* assume we can send more data now */
4724 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
4725 /* clear to send tags on this pad now */
4726 gst_qtdemux_push_tags (qtdemux, stream);
4737 /* activate the given segment number @seg_idx of @stream at time @offset.
4738 * @offset is an absolute global position over all the segments.
4740 * This will push out a NEWSEGMENT event with the right values and
4741 * position the stream index to the first decodable sample before
4745 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4746 guint32 seg_idx, GstClockTime offset)
4748 QtDemuxSegment *segment;
4749 guint32 index, kf_index;
4750 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
4752 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
4753 seg_idx, GST_TIME_ARGS (offset));
4755 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
4759 segment = &stream->segments[stream->segment_index];
4761 /* in the fragmented case, we pick a fragment that starts before our
4762 * desired position and rely on downstream to wait for a keyframe
4763 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
4764 * tfra entries tells us which trun/sample the key unit is in, but we don't
4765 * make use of this additional information at the moment) */
4766 if (qtdemux->fragmented) {
4767 stream->to_sample = G_MAXUINT32;
4771 /* We don't need to look for a sample in push-based */
4772 if (!qtdemux->pullbased)
4775 /* and move to the keyframe before the indicated media time of the
4777 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
4778 if (qtdemux->segment.rate >= 0) {
4779 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
4780 stream->to_sample = G_MAXUINT32;
4781 GST_DEBUG_OBJECT (stream->pad,
4782 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4783 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
4784 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4786 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
4787 stream->to_sample = index;
4788 GST_DEBUG_OBJECT (stream->pad,
4789 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4790 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
4791 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4794 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
4795 "this is an empty segment");
4799 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
4800 * encountered an error and printed a message so we return appropriately */
4804 /* we're at the right spot */
4805 if (index == stream->sample_index) {
4806 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
4810 /* find keyframe of the target index */
4811 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
4814 /* indent does stupid stuff with stream->samples[].timestamp */
4816 /* if we move forwards, we don't have to go back to the previous
4817 * keyframe since we already sent that. We can also just jump to
4818 * the keyframe right before the target index if there is one. */
4819 if (index > stream->sample_index) {
4820 /* moving forwards check if we move past a keyframe */
4821 if (kf_index > stream->sample_index) {
4822 GST_DEBUG_OBJECT (stream->pad,
4823 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4824 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4825 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4826 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4828 GST_DEBUG_OBJECT (stream->pad,
4829 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
4830 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
4831 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
4834 GST_DEBUG_OBJECT (stream->pad,
4835 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4836 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4837 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4838 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4846 /* prepare to get the current sample of @stream, getting essential values.
4848 * This function will also prepare and send the segment when needed.
4850 * Return FALSE if the stream is EOS.
4855 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
4856 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
4857 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
4858 gboolean * keyframe)
4860 QtDemuxSample *sample;
4861 GstClockTime time_position;
4864 g_return_val_if_fail (stream != NULL, FALSE);
4866 time_position = stream->time_position;
4867 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
4870 seg_idx = stream->segment_index;
4871 if (G_UNLIKELY (seg_idx == -1)) {
4872 /* find segment corresponding to time_position if we are looking
4874 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
4877 /* different segment, activate it, sample_index will be set. */
4878 if (G_UNLIKELY (stream->segment_index != seg_idx))
4879 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
4881 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->segments[stream->
4883 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
4885 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
4886 " prepare empty sample");
4889 *pts = *dts = time_position;
4890 *duration = seg->duration - (time_position - seg->time);
4897 if (stream->sample_index == -1)
4898 stream->sample_index = 0;
4900 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
4901 stream->sample_index, stream->n_samples);
4903 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
4904 if (!qtdemux->fragmented)
4907 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
4911 GST_OBJECT_LOCK (qtdemux);
4912 flow = qtdemux_add_fragmented_samples (qtdemux);
4913 GST_OBJECT_UNLOCK (qtdemux);
4915 if (flow != GST_FLOW_OK)
4918 while (stream->sample_index >= stream->n_samples);
4921 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4922 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4923 stream->sample_index);
4927 /* now get the info for the sample we're at */
4928 sample = &stream->samples[stream->sample_index];
4930 *dts = QTSAMPLE_DTS (stream, sample);
4931 *pts = QTSAMPLE_PTS (stream, sample);
4932 *offset = sample->offset;
4933 *size = sample->size;
4934 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
4935 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
4942 stream->time_position = GST_CLOCK_TIME_NONE;
4947 /* move to the next sample in @stream.
4949 * Moves to the next segment when needed.
4952 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
4954 QtDemuxSample *sample;
4955 QtDemuxSegment *segment;
4957 /* get current segment */
4958 segment = &stream->segments[stream->segment_index];
4960 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4961 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
4965 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
4966 /* Mark the stream as EOS */
4967 GST_DEBUG_OBJECT (qtdemux,
4968 "reached max allowed sample %u, mark EOS", stream->to_sample);
4969 stream->time_position = GST_CLOCK_TIME_NONE;
4973 /* move to next sample */
4974 stream->sample_index++;
4975 stream->offset_in_sample = 0;
4977 /* reached the last sample, we need the next segment */
4978 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
4981 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4982 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4983 stream->sample_index);
4987 /* get next sample */
4988 sample = &stream->samples[stream->sample_index];
4990 /* see if we are past the segment */
4991 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
4994 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
4995 /* inside the segment, update time_position, looks very familiar to
4996 * GStreamer segments, doesn't it? */
4997 stream->time_position =
4998 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
5000 /* not yet in segment, time does not yet increment. This means
5001 * that we are still prerolling keyframes to the decoder so it can
5002 * decode the first sample of the segment. */
5003 stream->time_position = segment->time;
5007 /* move to the next segment */
5010 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
5012 if (stream->segment_index == stream->n_segments - 1) {
5013 /* are we at the end of the last segment, we're EOS */
5014 stream->time_position = GST_CLOCK_TIME_NONE;
5016 /* else we're only at the end of the current segment */
5017 stream->time_position = segment->stop_time;
5019 /* make sure we select a new segment */
5021 /* accumulate previous segments */
5022 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
5023 stream->accumulated_base +=
5024 (stream->segment.stop -
5025 stream->segment.start) / ABS (stream->segment.rate);
5027 stream->segment_index = -1;
5032 gst_qtdemux_sync_streams (GstQTDemux * demux)
5036 if (demux->n_streams <= 1)
5039 for (i = 0; i < demux->n_streams; i++) {
5040 QtDemuxStream *stream;
5041 GstClockTime end_time;
5043 stream = demux->streams[i];
5048 /* TODO advance time on subtitle streams here, if any some day */
5050 /* some clips/trailers may have unbalanced streams at the end,
5051 * so send EOS on shorter stream to prevent stalling others */
5053 /* do not mess with EOS if SEGMENT seeking */
5054 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5057 if (demux->pullbased) {
5058 /* loop mode is sample time based */
5059 if (!STREAM_IS_EOS (stream))
5062 /* push mode is byte position based */
5063 if (stream->n_samples &&
5064 stream->samples[stream->n_samples - 1].offset >= demux->offset)
5068 if (stream->sent_eos)
5071 /* only act if some gap */
5072 end_time = stream->segments[stream->n_segments - 1].stop_time;
5073 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5074 ", stream end: %" GST_TIME_FORMAT,
5075 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5076 if (GST_CLOCK_TIME_IS_VALID (end_time)
5077 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5080 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5081 GST_PAD_NAME (stream->pad));
5082 stream->sent_eos = TRUE;
5083 event = gst_event_new_eos ();
5084 if (demux->segment_seqnum)
5085 gst_event_set_seqnum (event, demux->segment_seqnum);
5086 gst_pad_push_event (stream->pad, event);
5091 /* EOS and NOT_LINKED need to be combined. This means that we return:
5093 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
5094 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
5096 static GstFlowReturn
5097 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
5100 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
5103 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5106 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5108 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5112 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5113 * completely clipped
5115 * Should be used only with raw buffers */
5117 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5120 guint64 start, stop, cstart, cstop, diff;
5121 GstClockTime pts, duration;
5123 gint num_rate, denom_rate;
5128 osize = size = gst_buffer_get_size (buf);
5131 /* depending on the type, setup the clip parameters */
5132 if (stream->subtype == FOURCC_soun) {
5133 frame_size = stream->bytes_per_frame;
5134 num_rate = GST_SECOND;
5135 denom_rate = (gint) stream->rate;
5137 } else if (stream->subtype == FOURCC_vide) {
5139 num_rate = stream->fps_n;
5140 denom_rate = stream->fps_d;
5145 if (frame_size <= 0)
5146 goto bad_frame_size;
5148 /* we can only clip if we have a valid pts */
5149 pts = GST_BUFFER_PTS (buf);
5150 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5153 duration = GST_BUFFER_DURATION (buf);
5155 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5157 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5161 stop = start + duration;
5163 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5164 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5167 /* see if some clipping happened */
5168 diff = cstart - start;
5174 /* bring clipped time to samples and to bytes */
5175 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5178 GST_DEBUG_OBJECT (qtdemux,
5179 "clipping start to %" GST_TIME_FORMAT " %"
5180 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5186 diff = stop - cstop;
5191 /* bring clipped time to samples and then to bytes */
5192 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5194 GST_DEBUG_OBJECT (qtdemux,
5195 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5196 " bytes", GST_TIME_ARGS (cstop), diff);
5201 if (offset != 0 || size != osize)
5202 gst_buffer_resize (buf, offset, size);
5204 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5205 GST_BUFFER_PTS (buf) = pts;
5206 GST_BUFFER_DURATION (buf) = duration;
5210 /* dropped buffer */
5213 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5218 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5223 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5228 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5229 gst_buffer_unref (buf);
5235 gst_qtdemux_align_buffer (GstQTDemux * demux,
5236 GstBuffer * buffer, gsize alignment)
5240 gst_buffer_map (buffer, &map, GST_MAP_READ);
5242 if (map.size < sizeof (guintptr)) {
5243 gst_buffer_unmap (buffer, &map);
5247 if (((guintptr) map.data) & (alignment - 1)) {
5248 GstBuffer *new_buffer;
5249 GstAllocationParams params = { 0, alignment - 1, 0, 0, };
5251 new_buffer = gst_buffer_new_allocate (NULL,
5252 gst_buffer_get_size (buffer), ¶ms);
5254 /* Copy data "by hand", so ensure alignment is kept: */
5255 gst_buffer_fill (new_buffer, 0, map.data, map.size);
5257 gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
5258 GST_DEBUG_OBJECT (demux,
5259 "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
5262 gst_buffer_unmap (buffer, &map);
5263 gst_buffer_unref (buffer);
5268 gst_buffer_unmap (buffer, &map);
5272 /* the input buffer metadata must be writable,
5273 * but time/duration etc not yet set and need not be preserved */
5275 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5282 /* not many cases for now */
5283 if (G_UNLIKELY (stream->fourcc == FOURCC_mp4s)) {
5284 /* send a one time dvd clut event */
5285 if (stream->pending_event && stream->pad)
5286 gst_pad_push_event (stream->pad, stream->pending_event);
5287 stream->pending_event = NULL;
5290 if (G_UNLIKELY (stream->subtype != FOURCC_text
5291 && stream->subtype != FOURCC_sbtl &&
5292 stream->subtype != FOURCC_subp)) {
5296 gst_buffer_map (buf, &map, GST_MAP_READ);
5298 /* empty buffer is sent to terminate previous subtitle */
5299 if (map.size <= 2) {
5300 gst_buffer_unmap (buf, &map);
5301 gst_buffer_unref (buf);
5304 if (stream->subtype == FOURCC_subp) {
5305 /* That's all the processing needed for subpictures */
5306 gst_buffer_unmap (buf, &map);
5310 nsize = GST_READ_UINT16_BE (map.data);
5311 nsize = MIN (nsize, map.size - 2);
5313 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5316 /* takes care of UTF-8 validation or UTF-16 recognition,
5317 * no other encoding expected */
5318 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5319 gst_buffer_unmap (buf, &map);
5321 gst_buffer_unref (buf);
5322 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5324 /* this should not really happen unless the subtitle is corrupted */
5325 gst_buffer_unref (buf);
5329 /* FIXME ? convert optional subsequent style info to markup */
5334 /* Sets a buffer's attributes properly and pushes it downstream.
5335 * Also checks for additional actions and custom processing that may
5336 * need to be done first.
5338 static GstFlowReturn
5339 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
5340 QtDemuxStream * stream, GstBuffer * buf,
5341 GstClockTime dts, GstClockTime pts, GstClockTime duration,
5342 gboolean keyframe, GstClockTime position, guint64 byte_position)
5344 GstFlowReturn ret = GST_FLOW_OK;
5346 /* offset the timestamps according to the edit list */
5348 if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) {
5352 gst_buffer_map (buf, &map, GST_MAP_READ);
5353 url = g_strndup ((gchar *) map.data, map.size);
5354 gst_buffer_unmap (buf, &map);
5355 if (url != NULL && strlen (url) != 0) {
5356 /* we have RTSP redirect now */
5357 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5358 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
5359 gst_structure_new ("redirect",
5360 "new-location", G_TYPE_STRING, url, NULL)));
5361 qtdemux->posted_redirect = TRUE;
5363 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
5369 /* position reporting */
5370 if (qtdemux->segment.rate >= 0) {
5371 qtdemux->segment.position = position;
5372 gst_qtdemux_sync_streams (qtdemux);
5375 if (G_UNLIKELY (!stream->pad)) {
5376 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
5377 gst_buffer_unref (buf);
5381 /* send out pending buffers */
5382 while (stream->buffers) {
5383 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
5385 if (G_UNLIKELY (stream->discont)) {
5386 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5387 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
5388 stream->discont = FALSE;
5390 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5393 if (stream->alignment > 1)
5394 buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
5395 gst_pad_push (stream->pad, buffer);
5397 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
5400 /* we're going to modify the metadata */
5401 buf = gst_buffer_make_writable (buf);
5403 if (G_UNLIKELY (stream->need_process))
5404 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
5410 GST_BUFFER_DTS (buf) = dts;
5411 GST_BUFFER_PTS (buf) = pts;
5412 GST_BUFFER_DURATION (buf) = duration;
5413 GST_BUFFER_OFFSET (buf) = -1;
5414 GST_BUFFER_OFFSET_END (buf) = -1;
5416 if (G_UNLIKELY (stream->rgb8_palette))
5417 gst_buffer_append_memory (buf, gst_memory_ref (stream->rgb8_palette));
5419 if (G_UNLIKELY (stream->padding)) {
5420 gst_buffer_resize (buf, stream->padding, -1);
5423 if (G_UNLIKELY (qtdemux->element_index)) {
5424 GstClockTime stream_time;
5427 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
5429 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
5430 GST_LOG_OBJECT (qtdemux,
5431 "adding association %" GST_TIME_FORMAT "-> %"
5432 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
5433 gst_index_add_association (qtdemux->element_index,
5435 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
5436 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
5437 GST_FORMAT_BYTES, byte_position, NULL);
5442 if (stream->need_clip)
5443 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5445 if (G_UNLIKELY (buf == NULL))
5448 if (G_UNLIKELY (stream->discont)) {
5449 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5450 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5451 stream->discont = FALSE;
5453 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5457 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
5458 stream->on_keyframe = FALSE;
5460 stream->on_keyframe = TRUE;
5464 GST_LOG_OBJECT (qtdemux,
5465 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5466 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
5467 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
5468 GST_PAD_NAME (stream->pad));
5470 if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) {
5471 GstStructure *crypto_info;
5472 QtDemuxCencSampleSetInfo *info =
5473 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5477 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5478 gst_pad_push_event (stream->pad, event);
5481 if (info->crypto_info == NULL) {
5482 GST_DEBUG_OBJECT (qtdemux, "cenc metadata hasn't been parsed yet");
5483 gst_buffer_unref (buf);
5487 /* The end of the crypto_info array matches our n_samples position,
5488 * so count backward from there */
5489 index = stream->sample_index - stream->n_samples + info->crypto_info->len;
5490 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5491 /* steal structure from array */
5492 crypto_info = g_ptr_array_index (info->crypto_info, index);
5493 g_ptr_array_index (info->crypto_info, index) = NULL;
5494 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
5495 info->crypto_info->len);
5496 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5497 GST_ERROR_OBJECT (qtdemux, "failed to attach cenc metadata to buffer");
5499 GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
5500 index, stream->sample_index);
5504 if (stream->alignment > 1)
5505 buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
5507 ret = gst_pad_push (stream->pad, buf);
5509 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
5510 /* mark position in stream, we'll need this to know when to send GAP event */
5511 stream->segment.position = pts + duration;
5518 static const QtDemuxRandomAccessEntry *
5519 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5520 GstClockTime pos, gboolean after)
5522 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
5523 guint n_entries = stream->n_ra_entries;
5526 /* we assume the table is sorted */
5527 for (i = 0; i < n_entries; ++i) {
5528 if (entries[i].ts > pos)
5532 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
5533 * probably okay to assume that the index lists the very first fragment */
5540 return &entries[i - 1];
5544 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
5546 const QtDemuxRandomAccessEntry *best_entry = NULL;
5549 GST_OBJECT_LOCK (qtdemux);
5551 g_assert (qtdemux->n_streams > 0);
5553 for (i = 0; i < qtdemux->n_streams; i++) {
5554 const QtDemuxRandomAccessEntry *entry;
5555 QtDemuxStream *stream;
5556 gboolean is_audio_or_video;
5558 stream = qtdemux->streams[i];
5560 g_free (stream->samples);
5561 stream->samples = NULL;
5562 stream->n_samples = 0;
5563 stream->stbl_index = -1; /* no samples have yet been parsed */
5564 stream->sample_index = -1;
5566 if (stream->protection_scheme_info) {
5567 /* Clear out any old cenc crypto info entries as we'll move to a new moof */
5568 if (stream->protection_scheme_type == FOURCC_cenc) {
5569 QtDemuxCencSampleSetInfo *info =
5570 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5571 if (info->crypto_info) {
5572 g_ptr_array_free (info->crypto_info, TRUE);
5573 info->crypto_info = NULL;
5578 if (stream->ra_entries == NULL)
5581 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
5582 is_audio_or_video = TRUE;
5584 is_audio_or_video = FALSE;
5587 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
5588 stream->time_position, !is_audio_or_video);
5590 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
5591 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
5593 stream->pending_seek = entry;
5595 /* decide position to jump to just based on audio/video tracks, not subs */
5596 if (!is_audio_or_video)
5599 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
5603 if (best_entry == NULL) {
5604 GST_OBJECT_UNLOCK (qtdemux);
5608 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
5609 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
5610 GST_TIME_ARGS (qtdemux->streams[0]->time_position),
5611 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
5613 qtdemux->moof_offset = best_entry->moof_offset;
5615 qtdemux_add_fragmented_samples (qtdemux);
5617 GST_OBJECT_UNLOCK (qtdemux);
5621 static GstFlowReturn
5622 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
5624 GstFlowReturn ret = GST_FLOW_OK;
5625 GstBuffer *buf = NULL;
5626 QtDemuxStream *stream;
5627 GstClockTime min_time;
5629 GstClockTime dts = GST_CLOCK_TIME_NONE;
5630 GstClockTime pts = GST_CLOCK_TIME_NONE;
5631 GstClockTime duration = 0;
5632 gboolean keyframe = FALSE;
5633 guint sample_size = 0;
5639 gst_qtdemux_push_pending_newsegment (qtdemux);
5641 if (qtdemux->fragmented_seek_pending) {
5642 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
5643 gst_qtdemux_do_fragmented_seek (qtdemux);
5644 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
5645 qtdemux->fragmented_seek_pending = FALSE;
5648 /* Figure out the next stream sample to output, min_time is expressed in
5649 * global time and runs over the edit list segments. */
5650 min_time = G_MAXUINT64;
5652 for (i = 0; i < qtdemux->n_streams; i++) {
5653 GstClockTime position;
5655 stream = qtdemux->streams[i];
5656 position = stream->time_position;
5658 /* position of -1 is EOS */
5659 if (position != GST_CLOCK_TIME_NONE && position < min_time) {
5660 min_time = position;
5665 if (G_UNLIKELY (index == -1)) {
5666 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
5670 /* check for segment end */
5671 if (G_UNLIKELY (qtdemux->segment.stop != -1
5672 && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
5673 || (qtdemux->segment.rate < 0
5674 && qtdemux->segment.start > min_time))
5675 && qtdemux->streams[index]->on_keyframe)) {
5676 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
5677 qtdemux->streams[index]->time_position = GST_CLOCK_TIME_NONE;
5681 /* gap events for subtitle streams */
5682 for (i = 0; i < qtdemux->n_streams; i++) {
5683 stream = qtdemux->streams[i];
5684 if (stream->pad && (stream->subtype == FOURCC_subp
5685 || stream->subtype == FOURCC_text
5686 || stream->subtype == FOURCC_sbtl)) {
5687 /* send one second gap events until the stream catches up */
5688 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
5689 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
5690 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
5691 stream->segment.position + GST_SECOND < min_time) {
5693 gst_event_new_gap (stream->segment.position, GST_SECOND);
5694 gst_pad_push_event (stream->pad, gap);
5695 stream->segment.position += GST_SECOND;
5700 stream = qtdemux->streams[index];
5701 if (stream->new_caps) {
5702 gst_qtdemux_configure_stream (qtdemux, stream);
5703 qtdemux_do_allocation (qtdemux, stream);
5706 /* fetch info for the current sample of this stream */
5707 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
5708 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
5711 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
5712 if (G_UNLIKELY (qtdemux->
5713 segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
5714 if (stream->subtype == FOURCC_vide && !keyframe) {
5715 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on stream %d", index);
5720 GST_DEBUG_OBJECT (qtdemux,
5721 "pushing from stream %d, empty %d offset %" G_GUINT64_FORMAT
5722 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
5723 ", duration %" GST_TIME_FORMAT, index, empty, offset, sample_size,
5724 GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
5726 if (G_UNLIKELY (empty)) {
5727 /* empty segment, push a gap and move to the next one */
5728 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
5729 stream->segment.position = pts + duration;
5733 /* hmm, empty sample, skip and move to next sample */
5734 if (G_UNLIKELY (sample_size <= 0))
5737 /* last pushed sample was out of boundary, goto next sample */
5738 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
5741 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
5744 GST_DEBUG_OBJECT (qtdemux,
5745 "size %d larger than stream max_buffer_size %d, trimming",
5746 sample_size, stream->max_buffer_size);
5748 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
5751 if (qtdemux->cenc_aux_info_offset > 0) {
5754 GstBuffer *aux_info = NULL;
5756 /* pull the data stored before the sample */
5758 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
5759 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
5760 if (G_UNLIKELY (ret != GST_FLOW_OK))
5762 gst_buffer_map (aux_info, &map, GST_MAP_READ);
5763 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
5764 gst_byte_reader_init (&br, map.data + 8, map.size);
5765 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
5766 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
5767 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
5768 gst_buffer_unmap (aux_info, &map);
5769 gst_buffer_unref (aux_info);
5770 ret = GST_FLOW_ERROR;
5773 gst_buffer_unmap (aux_info, &map);
5774 gst_buffer_unref (aux_info);
5777 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
5780 if (stream->use_allocator) {
5781 /* if we have a per-stream allocator, use it */
5782 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
5785 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
5787 if (G_UNLIKELY (ret != GST_FLOW_OK))
5790 if (size != sample_size) {
5791 pts += gst_util_uint64_scale_int (GST_SECOND,
5792 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
5793 dts += gst_util_uint64_scale_int (GST_SECOND,
5794 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
5795 duration = gst_util_uint64_scale_int (GST_SECOND,
5796 size / stream->bytes_per_frame, stream->timescale);
5799 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
5800 dts, pts, duration, keyframe, min_time, offset);
5802 if (size != sample_size) {
5803 QtDemuxSample *sample = &stream->samples[stream->sample_index];
5804 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
5806 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
5807 sample->timestamp + stream->offset_in_sample / stream->bytes_per_frame);
5808 if (time_position >= segment->media_start) {
5809 /* inside the segment, update time_position, looks very familiar to
5810 * GStreamer segments, doesn't it? */
5811 stream->time_position = (time_position - segment->media_start) +
5814 /* not yet in segment, time does not yet increment. This means
5815 * that we are still prerolling keyframes to the decoder so it can
5816 * decode the first sample of the segment. */
5817 stream->time_position = segment->time;
5822 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
5823 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
5824 * we have no more data for the pad to push */
5825 if (ret == GST_FLOW_EOS)
5828 stream->offset_in_sample += size;
5829 if (stream->offset_in_sample >= sample_size) {
5830 gst_qtdemux_advance_sample (qtdemux, stream);
5835 gst_qtdemux_advance_sample (qtdemux, stream);
5843 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
5849 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
5850 /* EOS will be raised if all are EOS */
5857 gst_qtdemux_loop (GstPad * pad)
5859 GstQTDemux *qtdemux;
5863 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
5865 cur_offset = qtdemux->offset;
5866 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
5867 cur_offset, qt_demux_state_string (qtdemux->state));
5869 switch (qtdemux->state) {
5870 case QTDEMUX_STATE_INITIAL:
5871 case QTDEMUX_STATE_HEADER:
5872 ret = gst_qtdemux_loop_state_header (qtdemux);
5874 case QTDEMUX_STATE_MOVIE:
5875 ret = gst_qtdemux_loop_state_movie (qtdemux);
5876 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
5877 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
5885 /* if something went wrong, pause */
5886 if (ret != GST_FLOW_OK)
5890 gst_object_unref (qtdemux);
5896 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
5897 (NULL), ("streaming stopped, invalid state"));
5898 gst_pad_pause_task (pad);
5899 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5904 const gchar *reason = gst_flow_get_name (ret);
5906 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
5908 gst_pad_pause_task (pad);
5910 /* fatal errors need special actions */
5912 if (ret == GST_FLOW_EOS) {
5913 if (qtdemux->n_streams == 0) {
5914 /* we have no streams, post an error */
5915 gst_qtdemux_post_no_playable_stream_error (qtdemux);
5917 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
5920 if ((stop = qtdemux->segment.stop) == -1)
5921 stop = qtdemux->segment.duration;
5923 if (qtdemux->segment.rate >= 0) {
5924 GstMessage *message;
5927 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
5928 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5929 GST_FORMAT_TIME, stop);
5930 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
5931 if (qtdemux->segment_seqnum) {
5932 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
5933 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5935 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
5936 gst_qtdemux_push_event (qtdemux, event);
5938 GstMessage *message;
5941 /* For Reverse Playback */
5942 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
5943 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5944 GST_FORMAT_TIME, qtdemux->segment.start);
5945 event = gst_event_new_segment_done (GST_FORMAT_TIME,
5946 qtdemux->segment.start);
5947 if (qtdemux->segment_seqnum) {
5948 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
5949 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5951 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
5952 gst_qtdemux_push_event (qtdemux, event);
5957 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
5958 event = gst_event_new_eos ();
5959 if (qtdemux->segment_seqnum)
5960 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5961 gst_qtdemux_push_event (qtdemux, event);
5963 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
5964 GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
5965 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5974 * Returns if there are samples to be played.
5977 has_next_entry (GstQTDemux * demux)
5979 QtDemuxStream *stream;
5982 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
5984 for (i = 0; i < demux->n_streams; i++) {
5985 stream = demux->streams[i];
5987 if (stream->sample_index == -1) {
5988 stream->sample_index = 0;
5989 stream->offset_in_sample = 0;
5992 if (stream->sample_index >= stream->n_samples) {
5993 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
5996 GST_DEBUG_OBJECT (demux, "Found a sample");
6000 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
6007 * Returns the size of the first entry at the current offset.
6008 * If -1, there are none (which means EOS or empty file).
6011 next_entry_size (GstQTDemux * demux)
6013 QtDemuxStream *stream;
6016 guint64 smalloffs = (guint64) - 1;
6017 QtDemuxSample *sample;
6019 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
6022 for (i = 0; i < demux->n_streams; i++) {
6023 stream = demux->streams[i];
6025 if (stream->sample_index == -1) {
6026 stream->sample_index = 0;
6027 stream->offset_in_sample = 0;
6030 if (stream->sample_index >= stream->n_samples) {
6031 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
6035 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
6036 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
6037 stream->sample_index);
6041 sample = &stream->samples[stream->sample_index];
6043 GST_LOG_OBJECT (demux,
6044 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
6045 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
6046 sample->offset, sample->size);
6048 if (((smalloffs == -1)
6049 || (sample->offset < smalloffs)) && (sample->size)) {
6051 smalloffs = sample->offset;
6055 GST_LOG_OBJECT (demux,
6056 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
6057 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
6062 stream = demux->streams[smallidx];
6063 sample = &stream->samples[stream->sample_index];
6065 if (sample->offset >= demux->offset) {
6066 demux->todrop = sample->offset - demux->offset;
6067 return sample->size + demux->todrop;
6070 GST_DEBUG_OBJECT (demux,
6071 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
6076 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
6078 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
6080 gst_element_post_message (GST_ELEMENT_CAST (demux),
6081 gst_message_new_element (GST_OBJECT_CAST (demux),
6082 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
6086 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
6091 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
6094 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
6095 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
6096 GST_SEEK_TYPE_NONE, -1);
6098 /* store seqnum to drop flush events, they don't need to reach downstream */
6099 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
6100 res = gst_pad_push_event (demux->sinkpad, event);
6101 demux->offset_seek_seqnum = 0;
6106 /* check for seekable upstream, above and beyond a mere query */
6108 gst_qtdemux_check_seekability (GstQTDemux * demux)
6111 gboolean seekable = FALSE;
6112 gint64 start = -1, stop = -1;
6114 if (demux->upstream_size)
6117 if (demux->upstream_format_is_time)
6120 query = gst_query_new_seeking (GST_FORMAT_BYTES);
6121 if (!gst_pad_peer_query (demux->sinkpad, query)) {
6122 GST_DEBUG_OBJECT (demux, "seeking query failed");
6126 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
6128 /* try harder to query upstream size if we didn't get it the first time */
6129 if (seekable && stop == -1) {
6130 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
6131 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
6134 /* if upstream doesn't know the size, it's likely that it's not seekable in
6135 * practice even if it technically may be seekable */
6136 if (seekable && (start != 0 || stop <= start)) {
6137 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
6142 gst_query_unref (query);
6144 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
6145 G_GUINT64_FORMAT ")", seekable, start, stop);
6146 demux->upstream_seekable = seekable;
6147 demux->upstream_size = seekable ? stop : -1;
6151 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
6153 g_return_if_fail (bytes <= demux->todrop);
6155 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
6156 gst_adapter_flush (demux->adapter, bytes);
6157 demux->neededbytes -= bytes;
6158 demux->offset += bytes;
6159 demux->todrop -= bytes;
6163 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
6165 if (G_UNLIKELY (demux->pending_newsegment)) {
6168 gst_qtdemux_push_pending_newsegment (demux);
6169 /* clear to send tags on all streams */
6170 for (i = 0; i < demux->n_streams; i++) {
6171 QtDemuxStream *stream;
6172 stream = demux->streams[i];
6173 gst_qtdemux_push_tags (demux, stream);
6174 if (stream->sparse) {
6175 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
6176 gst_pad_push_event (stream->pad,
6177 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
6184 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
6185 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
6187 GstClockTime ts, dur;
6192 stream->segments[segment_index].duration - (pos -
6193 stream->segments[segment_index].time);
6194 gap = gst_event_new_gap (ts, dur);
6195 stream->time_position += dur;
6197 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
6198 "segment: %" GST_PTR_FORMAT, gap);
6199 gst_pad_push_event (stream->pad, gap);
6203 gst_qtdemux_stream_send_initial_gap_segments (GstQTDemux * demux,
6204 QtDemuxStream * stream)
6208 /* Push any initial gap segments before proceeding to the
6210 for (i = 0; i < stream->n_segments; i++) {
6211 gst_qtdemux_activate_segment (demux, stream, i, stream->time_position);
6213 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
6214 gst_qtdemux_send_gap_for_segment (demux, stream, i,
6215 stream->time_position);
6217 /* Only support empty segment at the beginning followed by
6218 * one non-empty segment, this was checked when parsing the
6219 * edts atom, arriving here is unexpected */
6220 g_assert (i + 1 == stream->n_segments);
6226 static GstFlowReturn
6227 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
6231 demux = GST_QTDEMUX (parent);
6233 GST_DEBUG_OBJECT (demux,
6234 "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
6235 " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
6236 G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
6237 GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
6238 gst_buffer_get_size (inbuf), demux->offset);
6240 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
6241 gboolean is_gap_input = FALSE;
6244 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
6246 for (i = 0; i < demux->n_streams; i++) {
6247 demux->streams[i]->discont = TRUE;
6250 /* Check if we can land back on our feet in the case where upstream is
6251 * handling the seeking/pushing of samples with gaps in between (like
6252 * in the case of trick-mode DASH for example) */
6253 if (demux->upstream_format_is_time
6254 && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
6256 for (i = 0; i < demux->n_streams; i++) {
6258 GST_LOG_OBJECT (demux,
6259 "Stream #%d , checking if offset %" G_GUINT64_FORMAT
6260 " is a sample start", i, GST_BUFFER_OFFSET (inbuf));
6262 gst_qtdemux_find_index_for_given_media_offset_linear (demux,
6263 demux->streams[i], GST_BUFFER_OFFSET (inbuf));
6265 QtDemuxSample *sample = &demux->streams[i]->samples[res];
6266 GST_LOG_OBJECT (demux,
6267 "Checking if sample %d from stream %d is valid (offset:%"
6268 G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res, i,
6269 sample->offset, sample->size);
6270 if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
6271 GST_LOG_OBJECT (demux,
6272 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
6274 is_gap_input = TRUE;
6275 /* We can go back to standard playback mode */
6276 demux->state = QTDEMUX_STATE_MOVIE;
6277 /* Remember which sample this stream is at */
6278 demux->streams[i]->sample_index = res;
6279 /* Finally update all push-based values to the expected values */
6280 demux->neededbytes = demux->streams[i]->samples[res].size;
6281 demux->offset = GST_BUFFER_OFFSET (inbuf);
6283 demux->mdatsize - demux->offset + demux->mdatoffset;
6288 if (!is_gap_input) {
6289 /* Reset state if it's a real discont */
6290 demux->neededbytes = 16;
6291 demux->state = QTDEMUX_STATE_INITIAL;
6292 demux->offset = GST_BUFFER_OFFSET (inbuf);
6295 /* Reverse fragmented playback, need to flush all we have before
6296 * consuming a new fragment.
6297 * The samples array have the timestamps calculated by accumulating the
6298 * durations but this won't work for reverse playback of fragments as
6299 * the timestamps of a subsequent fragment should be smaller than the
6300 * previously received one. */
6301 if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
6302 gst_qtdemux_process_adapter (demux, TRUE);
6303 for (i = 0; i < demux->n_streams; i++)
6304 gst_qtdemux_stream_flush_samples_data (demux, demux->streams[i]);
6308 gst_adapter_push (demux->adapter, inbuf);
6310 GST_DEBUG_OBJECT (demux,
6311 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
6312 demux->neededbytes, gst_adapter_available (demux->adapter));
6314 return gst_qtdemux_process_adapter (demux, FALSE);
6317 static GstFlowReturn
6318 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
6320 GstFlowReturn ret = GST_FLOW_OK;
6322 /* we never really mean to buffer that much */
6323 if (demux->neededbytes == -1) {
6327 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
6328 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
6330 #ifndef GST_DISABLE_GST_DEBUG
6332 guint64 discont_offset, distance_from_discont;
6334 discont_offset = gst_adapter_offset_at_discont (demux->adapter);
6335 distance_from_discont =
6336 gst_adapter_distance_from_discont (demux->adapter);
6338 GST_DEBUG_OBJECT (demux,
6339 "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
6340 " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
6341 " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
6342 demux->offset, discont_offset, distance_from_discont);
6346 switch (demux->state) {
6347 case QTDEMUX_STATE_INITIAL:{
6352 gst_qtdemux_check_seekability (demux);
6354 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6356 /* get fourcc/length, set neededbytes */
6357 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
6359 gst_adapter_unmap (demux->adapter);
6361 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
6362 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
6364 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6365 (_("This file is invalid and cannot be played.")),
6366 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
6367 GST_FOURCC_ARGS (fourcc)));
6368 ret = GST_FLOW_ERROR;
6371 if (fourcc == FOURCC_mdat) {
6372 gint next_entry = next_entry_size (demux);
6373 if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
6374 /* we have the headers, start playback */
6375 demux->state = QTDEMUX_STATE_MOVIE;
6376 demux->neededbytes = next_entry;
6377 demux->mdatleft = size;
6378 demux->mdatsize = demux->mdatleft;
6380 /* no headers yet, try to get them */
6383 guint64 old, target;
6386 old = demux->offset;
6387 target = old + size;
6389 /* try to jump over the atom with a seek */
6390 /* only bother if it seems worth doing so,
6391 * and avoids possible upstream/server problems */
6392 if (demux->upstream_seekable &&
6393 demux->upstream_size > 4 * (1 << 20)) {
6394 res = qtdemux_seek_offset (demux, target);
6396 GST_DEBUG_OBJECT (demux, "skipping seek");
6401 GST_DEBUG_OBJECT (demux, "seek success");
6402 /* remember the offset fo the first mdat so we can seek back to it
6403 * after we have the headers */
6404 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
6405 demux->first_mdat = old;
6406 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
6409 /* seek worked, continue reading */
6410 demux->offset = target;
6411 demux->neededbytes = 16;
6412 demux->state = QTDEMUX_STATE_INITIAL;
6414 /* seek failed, need to buffer */
6415 demux->offset = old;
6416 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
6417 /* there may be multiple mdat (or alike) buffers */
6419 if (demux->mdatbuffer)
6420 bs = gst_buffer_get_size (demux->mdatbuffer);
6423 if (size + bs > 10 * (1 << 20))
6425 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
6426 demux->neededbytes = size;
6427 if (!demux->mdatbuffer)
6428 demux->mdatoffset = demux->offset;
6431 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
6432 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6433 (_("This file is invalid and cannot be played.")),
6434 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
6435 GST_FOURCC_ARGS (fourcc), size));
6436 ret = GST_FLOW_ERROR;
6439 /* this means we already started buffering and still no moov header,
6440 * let's continue buffering everything till we get moov */
6441 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
6442 || fourcc == FOURCC_moof))
6444 demux->neededbytes = size;
6445 demux->state = QTDEMUX_STATE_HEADER;
6449 case QTDEMUX_STATE_HEADER:{
6453 GST_DEBUG_OBJECT (demux, "In header");
6455 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6457 /* parse the header */
6458 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
6460 if (fourcc == FOURCC_moov) {
6463 /* in usual fragmented setup we could try to scan for more
6464 * and end up at the the moov (after mdat) again */
6465 if (demux->got_moov && demux->n_streams > 0 &&
6467 || demux->last_moov_offset == demux->offset)) {
6468 GST_DEBUG_OBJECT (demux,
6469 "Skipping moov atom as we have (this) one already");
6471 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
6473 if (demux->got_moov && demux->fragmented) {
6474 GST_DEBUG_OBJECT (demux,
6475 "Got a second moov, clean up data from old one");
6476 if (demux->moov_node_compressed) {
6477 g_node_destroy (demux->moov_node_compressed);
6478 if (demux->moov_node)
6479 g_free (demux->moov_node->data);
6481 demux->moov_node_compressed = NULL;
6482 if (demux->moov_node)
6483 g_node_destroy (demux->moov_node);
6484 demux->moov_node = NULL;
6486 /* prepare newsegment to send when streaming actually starts */
6487 if (!demux->pending_newsegment) {
6488 demux->pending_newsegment =
6489 gst_event_new_segment (&demux->segment);
6490 if (demux->segment_seqnum)
6491 gst_event_set_seqnum (demux->pending_newsegment,
6492 demux->segment_seqnum);
6496 demux->last_moov_offset = demux->offset;
6498 qtdemux_parse_moov (demux, data, demux->neededbytes);
6499 qtdemux_node_dump (demux, demux->moov_node);
6500 qtdemux_parse_tree (demux);
6501 qtdemux_prepare_streams (demux);
6502 if (!demux->got_moov)
6503 qtdemux_expose_streams (demux);
6506 for (n = 0; n < demux->n_streams; n++) {
6507 QtDemuxStream *stream = demux->streams[n];
6509 gst_qtdemux_configure_stream (demux, stream);
6513 demux->got_moov = TRUE;
6514 gst_qtdemux_check_send_pending_segment (demux);
6516 /* fragmented streams headers shouldn't contain edts atoms */
6517 if (!demux->fragmented) {
6518 for (n = 0; n < demux->n_streams; n++) {
6519 gst_qtdemux_stream_send_initial_gap_segments (demux,
6524 if (demux->moov_node_compressed) {
6525 g_node_destroy (demux->moov_node_compressed);
6526 g_free (demux->moov_node->data);
6528 demux->moov_node_compressed = NULL;
6529 g_node_destroy (demux->moov_node);
6530 demux->moov_node = NULL;
6531 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
6533 } else if (fourcc == FOURCC_moof) {
6534 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
6536 GstClockTime prev_pts;
6537 guint64 prev_offset;
6538 guint64 adapter_discont_offset, adapter_discont_dist;
6540 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
6543 * The timestamp of the moof buffer is relevant as some scenarios
6544 * won't have the initial timestamp in the atoms. Whenever a new
6545 * buffer has started, we get that buffer's PTS and use it as a base
6546 * timestamp for the trun entries.
6548 * To keep track of the current buffer timestamp and starting point
6549 * we use gst_adapter_prev_pts that gives us the PTS and the distance
6550 * from the beggining of the buffer, with the distance and demux->offset
6551 * we know if it is still the same buffer or not.
6553 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
6554 prev_offset = demux->offset - dist;
6555 if (demux->fragment_start_offset == -1
6556 || prev_offset > demux->fragment_start_offset) {
6557 demux->fragment_start_offset = prev_offset;
6558 demux->fragment_start = prev_pts;
6559 GST_DEBUG_OBJECT (demux,
6560 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
6561 GST_TIME_FORMAT, demux->fragment_start_offset,
6562 GST_TIME_ARGS (demux->fragment_start));
6565 /* We can't use prev_offset() here because this would require
6566 * upstream to set consistent and correct offsets on all buffers
6567 * since the discont. Nothing ever did that in the past and we
6568 * would break backwards compatibility here then.
6569 * Instead take the offset we had at the last discont and count
6570 * the bytes from there. This works with old code as there would
6571 * be no discont between moov and moof, and also works with
6572 * adaptivedemux which correctly sets offset and will set the
6573 * DISCONT flag accordingly when needed.
6575 * We also only do this for upstream TIME segments as otherwise
6576 * there are potential backwards compatibility problems with
6577 * seeking in PUSH mode and upstream providing inconsistent
6579 adapter_discont_offset =
6580 gst_adapter_offset_at_discont (demux->adapter);
6581 adapter_discont_dist =
6582 gst_adapter_distance_from_discont (demux->adapter);
6584 GST_DEBUG_OBJECT (demux,
6585 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
6586 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
6587 demux->offset, adapter_discont_offset, adapter_discont_dist);
6589 if (demux->upstream_format_is_time) {
6590 demux->moof_offset = adapter_discont_offset;
6591 if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
6592 demux->moof_offset += adapter_discont_dist;
6593 if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
6594 demux->moof_offset = demux->offset;
6596 demux->moof_offset = demux->offset;
6599 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
6600 demux->moof_offset, NULL)) {
6601 gst_adapter_unmap (demux->adapter);
6602 ret = GST_FLOW_ERROR;
6605 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
6606 if (demux->mss_mode && !demux->exposed) {
6607 if (!demux->pending_newsegment) {
6608 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
6609 demux->pending_newsegment =
6610 gst_event_new_segment (&demux->segment);
6611 if (demux->segment_seqnum)
6612 gst_event_set_seqnum (demux->pending_newsegment,
6613 demux->segment_seqnum);
6615 qtdemux_expose_streams (demux);
6618 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
6620 } else if (fourcc == FOURCC_ftyp) {
6621 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
6622 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
6623 } else if (fourcc == FOURCC_uuid) {
6624 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
6625 qtdemux_parse_uuid (demux, data, demux->neededbytes);
6626 } else if (fourcc == FOURCC_sidx) {
6627 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
6628 qtdemux_parse_sidx (demux, data, demux->neededbytes);
6632 /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
6635 /* [free] is a padding atom */
6636 GST_DEBUG_OBJECT (demux,
6637 "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
6638 GST_FOURCC_ARGS (fourcc));
6641 GST_WARNING_OBJECT (demux,
6642 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
6643 GST_FOURCC_ARGS (fourcc));
6644 /* Let's jump that one and go back to initial state */
6648 gst_adapter_unmap (demux->adapter);
6651 if (demux->mdatbuffer && demux->n_streams) {
6652 gsize remaining_data_size = 0;
6654 /* the mdat was before the header */
6655 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
6656 demux->n_streams, demux->mdatbuffer);
6657 /* restore our adapter/offset view of things with upstream;
6658 * put preceding buffered data ahead of current moov data.
6659 * This should also handle evil mdat, moov, mdat cases and alike */
6660 gst_adapter_flush (demux->adapter, demux->neededbytes);
6662 /* Store any remaining data after the mdat for later usage */
6663 remaining_data_size = gst_adapter_available (demux->adapter);
6664 if (remaining_data_size > 0) {
6665 g_assert (demux->restoredata_buffer == NULL);
6666 demux->restoredata_buffer =
6667 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
6668 demux->restoredata_offset = demux->offset + demux->neededbytes;
6669 GST_DEBUG_OBJECT (demux,
6670 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
6671 G_GUINT64_FORMAT, remaining_data_size,
6672 demux->restoredata_offset);
6675 gst_adapter_push (demux->adapter, demux->mdatbuffer);
6676 demux->mdatbuffer = NULL;
6677 demux->offset = demux->mdatoffset;
6678 demux->neededbytes = next_entry_size (demux);
6679 demux->state = QTDEMUX_STATE_MOVIE;
6680 demux->mdatleft = gst_adapter_available (demux->adapter);
6681 demux->mdatsize = demux->mdatleft;
6683 GST_DEBUG_OBJECT (demux, "Carrying on normally");
6684 gst_adapter_flush (demux->adapter, demux->neededbytes);
6686 /* only go back to the mdat if there are samples to play */
6687 if (demux->got_moov && demux->first_mdat != -1
6688 && has_next_entry (demux)) {
6691 /* we need to seek back */
6692 res = qtdemux_seek_offset (demux, demux->first_mdat);
6694 demux->offset = demux->first_mdat;
6696 GST_DEBUG_OBJECT (demux, "Seek back failed");
6699 demux->offset += demux->neededbytes;
6701 demux->neededbytes = 16;
6702 demux->state = QTDEMUX_STATE_INITIAL;
6707 case QTDEMUX_STATE_BUFFER_MDAT:{
6711 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
6713 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6714 gst_buffer_extract (buf, 0, fourcc, 4);
6715 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
6716 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
6717 if (demux->mdatbuffer)
6718 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
6720 demux->mdatbuffer = buf;
6721 demux->offset += demux->neededbytes;
6722 demux->neededbytes = 16;
6723 demux->state = QTDEMUX_STATE_INITIAL;
6724 gst_qtdemux_post_progress (demux, 1, 1);
6728 case QTDEMUX_STATE_MOVIE:{
6729 QtDemuxStream *stream = NULL;
6730 QtDemuxSample *sample;
6732 GstClockTime dts, pts, duration;
6735 GST_DEBUG_OBJECT (demux,
6736 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
6738 if (demux->fragmented) {
6739 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
6741 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
6742 /* if needed data starts within this atom,
6743 * then it should not exceed this atom */
6744 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
6745 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6746 (_("This file is invalid and cannot be played.")),
6747 ("sample data crosses atom boundary"));
6748 ret = GST_FLOW_ERROR;
6751 demux->mdatleft -= demux->neededbytes;
6753 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
6754 /* so we are dropping more than left in this atom */
6755 gst_qtdemux_drop_data (demux, demux->mdatleft);
6756 demux->mdatleft = 0;
6758 /* need to resume atom parsing so we do not miss any other pieces */
6759 demux->state = QTDEMUX_STATE_INITIAL;
6760 demux->neededbytes = 16;
6762 /* check if there was any stored post mdat data from previous buffers */
6763 if (demux->restoredata_buffer) {
6764 g_assert (gst_adapter_available (demux->adapter) == 0);
6766 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
6767 demux->restoredata_buffer = NULL;
6768 demux->offset = demux->restoredata_offset;
6775 if (demux->todrop) {
6776 if (demux->cenc_aux_info_offset > 0) {
6780 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
6781 data = gst_adapter_map (demux->adapter, demux->todrop);
6782 gst_byte_reader_init (&br, data + 8, demux->todrop);
6783 if (!qtdemux_parse_cenc_aux_info (demux, demux->streams[0], &br,
6784 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
6785 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
6786 ret = GST_FLOW_ERROR;
6787 gst_adapter_unmap (demux->adapter);
6788 g_free (demux->cenc_aux_info_sizes);
6789 demux->cenc_aux_info_sizes = NULL;
6792 demux->cenc_aux_info_offset = 0;
6793 g_free (demux->cenc_aux_info_sizes);
6794 demux->cenc_aux_info_sizes = NULL;
6795 gst_adapter_unmap (demux->adapter);
6797 gst_qtdemux_drop_data (demux, demux->todrop);
6801 /* initial newsegment sent here after having added pads,
6802 * possible others in sink_event */
6803 gst_qtdemux_check_send_pending_segment (demux);
6805 /* Figure out which stream this packet belongs to */
6806 for (i = 0; i < demux->n_streams; i++) {
6807 stream = demux->streams[i];
6808 if (stream->sample_index >= stream->n_samples)
6810 GST_LOG_OBJECT (demux,
6811 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
6812 " / size:%d)", i, stream->sample_index,
6813 stream->samples[stream->sample_index].offset,
6814 stream->samples[stream->sample_index].size);
6816 if (stream->samples[stream->sample_index].offset == demux->offset)
6820 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
6821 goto unknown_stream;
6823 if (stream->new_caps) {
6824 gst_qtdemux_configure_stream (demux, stream);
6827 /* Put data in a buffer, set timestamps, caps, ... */
6828 sample = &stream->samples[stream->sample_index];
6830 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
6831 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
6832 GST_FOURCC_ARGS (stream->fourcc));
6834 dts = QTSAMPLE_DTS (stream, sample);
6835 pts = QTSAMPLE_PTS (stream, sample);
6836 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
6837 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
6839 /* check for segment end */
6840 if (G_UNLIKELY (demux->segment.stop != -1
6841 && demux->segment.stop <= pts && stream->on_keyframe)) {
6842 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
6843 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
6845 /* skip this data, stream is EOS */
6846 gst_adapter_flush (demux->adapter, demux->neededbytes);
6848 /* check if all streams are eos */
6850 for (i = 0; i < demux->n_streams; i++) {
6851 if (!STREAM_IS_EOS (demux->streams[i])) {
6857 if (ret == GST_FLOW_EOS) {
6858 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
6865 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6867 /* FIXME: should either be an assert or a plain check */
6868 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
6870 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
6871 dts, pts, duration, keyframe, dts, demux->offset);
6875 ret = gst_qtdemux_combine_flows (demux, stream, ret);
6877 /* skip this data, stream is EOS */
6878 gst_adapter_flush (demux->adapter, demux->neededbytes);
6881 stream->sample_index++;
6882 stream->offset_in_sample = 0;
6884 /* update current offset and figure out size of next buffer */
6885 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
6886 demux->offset, demux->neededbytes);
6887 demux->offset += demux->neededbytes;
6888 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
6891 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
6892 if (demux->fragmented) {
6893 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
6894 /* there may be more to follow, only finish this atom */
6895 demux->todrop = demux->mdatleft;
6896 demux->neededbytes = demux->todrop;
6901 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
6902 goto non_ok_unlinked_flow;
6911 /* when buffering movie data, at least show user something is happening */
6912 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
6913 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
6914 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
6915 demux->neededbytes);
6922 non_ok_unlinked_flow:
6924 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
6925 gst_flow_get_name (ret));
6930 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
6931 ret = GST_FLOW_ERROR;
6936 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
6942 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
6943 (NULL), ("qtdemuxer invalid state %d", demux->state));
6944 ret = GST_FLOW_ERROR;
6949 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
6950 (NULL), ("no 'moov' atom within the first 10 MB"));
6951 ret = GST_FLOW_ERROR;
6957 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
6962 query = gst_query_new_scheduling ();
6964 if (!gst_pad_peer_query (sinkpad, query)) {
6965 gst_query_unref (query);
6969 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
6970 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
6971 gst_query_unref (query);
6976 GST_DEBUG_OBJECT (sinkpad, "activating pull");
6977 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
6981 GST_DEBUG_OBJECT (sinkpad, "activating push");
6982 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
6987 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
6988 GstPadMode mode, gboolean active)
6991 GstQTDemux *demux = GST_QTDEMUX (parent);
6994 case GST_PAD_MODE_PUSH:
6995 demux->pullbased = FALSE;
6998 case GST_PAD_MODE_PULL:
7000 demux->pullbased = TRUE;
7001 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
7004 res = gst_pad_stop_task (sinkpad);
7016 qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
7022 memset (&z, 0, sizeof (z));
7027 if ((ret = inflateInit (&z)) != Z_OK) {
7028 GST_ERROR ("inflateInit() returned %d", ret);
7032 z.next_in = z_buffer;
7033 z.avail_in = z_length;
7035 buffer = (guint8 *) g_malloc (*length);
7036 z.avail_out = *length;
7037 z.next_out = (Bytef *) buffer;
7039 ret = inflate (&z, Z_NO_FLUSH);
7040 if (ret == Z_STREAM_END) {
7042 } else if (ret != Z_OK) {
7043 GST_WARNING ("inflate() returned %d", ret);
7048 buffer = (guint8 *) g_realloc (buffer, *length);
7049 z.next_out = (Bytef *) (buffer + z.total_out);
7050 z.avail_out += 4096;
7051 } while (z.avail_in > 0);
7053 if (ret != Z_STREAM_END) {
7058 *length = z.total_out;
7065 #endif /* HAVE_ZLIB */
7068 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
7072 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
7074 /* counts as header data */
7075 qtdemux->header_size += length;
7077 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
7078 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
7080 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
7087 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
7088 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
7089 if (dcom == NULL || cmvd == NULL)
7090 goto invalid_compression;
7092 dcom_len = QT_UINT32 (dcom->data);
7094 goto invalid_compression;
7096 method = QT_FOURCC ((guint8 *) dcom->data + 8);
7100 guint uncompressed_length;
7101 guint compressed_length;
7105 cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
7107 goto invalid_compression;
7109 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
7110 compressed_length = cmvd_len - 12;
7111 GST_LOG ("length = %u", uncompressed_length);
7114 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
7115 compressed_length, &uncompressed_length);
7118 qtdemux->moov_node_compressed = qtdemux->moov_node;
7119 qtdemux->moov_node = g_node_new (buf);
7121 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
7122 uncompressed_length);
7126 #endif /* HAVE_ZLIB */
7128 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
7129 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
7136 invalid_compression:
7138 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
7144 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
7147 while (G_UNLIKELY (buf < end)) {
7151 if (G_UNLIKELY (buf + 4 > end)) {
7152 GST_LOG_OBJECT (qtdemux, "buffer overrun");
7155 len = QT_UINT32 (buf);
7156 if (G_UNLIKELY (len == 0)) {
7157 GST_LOG_OBJECT (qtdemux, "empty container");
7160 if (G_UNLIKELY (len < 8)) {
7161 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
7164 if (G_UNLIKELY (len > (end - buf))) {
7165 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
7166 (gint) (end - buf));
7170 child = g_node_new ((guint8 *) buf);
7171 g_node_append (node, child);
7172 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
7173 qtdemux_parse_node (qtdemux, child, buf, len);
7181 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
7184 int len = QT_UINT32 (xdxt->data);
7185 guint8 *buf = xdxt->data;
7186 guint8 *end = buf + len;
7189 /* skip size and type */
7197 size = QT_UINT32 (buf);
7198 type = QT_FOURCC (buf + 4);
7200 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
7202 if (buf + size > end || size <= 0)
7208 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
7209 GST_FOURCC_ARGS (type));
7213 buffer = gst_buffer_new_and_alloc (size);
7214 gst_buffer_fill (buffer, 0, buf, size);
7215 stream->buffers = g_slist_append (stream->buffers, buffer);
7216 GST_LOG_OBJECT (qtdemux, "parsing theora header");
7219 buffer = gst_buffer_new_and_alloc (size);
7220 gst_buffer_fill (buffer, 0, buf, size);
7221 stream->buffers = g_slist_append (stream->buffers, buffer);
7222 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
7225 buffer = gst_buffer_new_and_alloc (size);
7226 gst_buffer_fill (buffer, 0, buf, size);
7227 stream->buffers = g_slist_append (stream->buffers, buffer);
7228 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
7231 GST_WARNING_OBJECT (qtdemux,
7232 "unknown theora cookie %" GST_FOURCC_FORMAT,
7233 GST_FOURCC_ARGS (type));
7242 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
7246 guint32 node_length = 0;
7247 const QtNodeType *type;
7250 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
7252 if (G_UNLIKELY (length < 8))
7253 goto not_enough_data;
7255 node_length = QT_UINT32 (buffer);
7256 fourcc = QT_FOURCC (buffer + 4);
7258 /* ignore empty nodes */
7259 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
7262 type = qtdemux_type_get (fourcc);
7264 end = buffer + length;
7266 GST_LOG_OBJECT (qtdemux,
7267 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
7268 GST_FOURCC_ARGS (fourcc), node_length, type->name);
7270 if (node_length > length)
7271 goto broken_atom_size;
7273 if (type->flags & QT_FLAG_CONTAINER) {
7274 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
7279 if (node_length < 20) {
7280 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
7283 GST_DEBUG_OBJECT (qtdemux,
7284 "parsing stsd (sample table, sample description) atom");
7285 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
7286 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7297 /* also read alac (or whatever) in stead of mp4a in the following,
7298 * since a similar layout is used in other cases as well */
7299 if (fourcc == FOURCC_mp4a)
7301 else if (fourcc == FOURCC_fLaC)
7306 /* There are two things we might encounter here: a true mp4a atom, and
7307 an mp4a entry in an stsd atom. The latter is what we're interested
7308 in, and it looks like an atom, but isn't really one. The true mp4a
7309 atom is short, so we detect it based on length here. */
7310 if (length < min_size) {
7311 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7312 GST_FOURCC_ARGS (fourcc));
7316 /* 'version' here is the sound sample description version. Types 0 and
7317 1 are documented in the QTFF reference, but type 2 is not: it's
7318 described in Apple header files instead (struct SoundDescriptionV2
7320 version = QT_UINT16 (buffer + 16);
7322 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
7323 GST_FOURCC_ARGS (fourcc), version);
7325 /* parse any esds descriptors */
7337 GST_WARNING_OBJECT (qtdemux,
7338 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
7339 GST_FOURCC_ARGS (fourcc), version);
7344 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7370 /* codec_data is contained inside these atoms, which all have
7371 * the same format. */
7372 /* video sample description size is 86 bytes without extension.
7373 * node_length have to be bigger than 86 bytes because video sample
7374 * description can include extenstions such as esds, fiel, glbl, etc. */
7375 if (node_length < 86) {
7376 GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
7377 " sample description length too short (%u < 86)",
7378 GST_FOURCC_ARGS (fourcc), node_length);
7382 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
7383 GST_FOURCC_ARGS (fourcc));
7385 /* version (2 bytes) : this is set to 0, unless a compressor has changed
7387 * revision level (2 bytes) : must be set to 0. */
7388 version = QT_UINT32 (buffer + 16);
7389 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
7391 /* compressor name : PASCAL string and informative purposes
7392 * first byte : the number of bytes to be displayed.
7393 * it has to be less than 32 because it is reserved
7394 * space of 32 bytes total including itself. */
7395 str_len = QT_UINT8 (buffer + 50);
7397 GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
7398 (char *) buffer + 51);
7400 GST_WARNING_OBJECT (qtdemux,
7401 "compressorname length too big (%u > 31)", str_len);
7403 GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
7405 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
7410 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
7411 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
7416 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
7417 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
7418 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7427 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7428 GST_FOURCC_ARGS (fourcc));
7432 version = QT_UINT32 (buffer + 12);
7433 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
7440 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
7445 if (length < offset) {
7446 GST_WARNING_OBJECT (qtdemux,
7447 "skipping too small %" GST_FOURCC_FORMAT " box",
7448 GST_FOURCC_ARGS (fourcc));
7451 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7457 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
7462 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
7467 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
7471 if (!strcmp (type->name, "unknown"))
7472 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
7476 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
7477 GST_FOURCC_ARGS (fourcc));
7483 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7484 (_("This file is corrupt and cannot be played.")),
7485 ("Not enough data for an atom header, got only %u bytes", length));
7490 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7491 (_("This file is corrupt and cannot be played.")),
7492 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
7493 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
7500 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
7504 guint32 child_fourcc;
7506 for (child = g_node_first_child (node); child;
7507 child = g_node_next_sibling (child)) {
7508 buffer = (guint8 *) child->data;
7510 child_fourcc = QT_FOURCC (buffer + 4);
7512 if (G_UNLIKELY (child_fourcc == fourcc)) {
7520 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
7521 GstByteReader * parser)
7525 guint32 child_fourcc, child_len;
7527 for (child = g_node_first_child (node); child;
7528 child = g_node_next_sibling (child)) {
7529 buffer = (guint8 *) child->data;
7531 child_len = QT_UINT32 (buffer);
7532 child_fourcc = QT_FOURCC (buffer + 4);
7534 if (G_UNLIKELY (child_fourcc == fourcc)) {
7535 if (G_UNLIKELY (child_len < (4 + 4)))
7537 /* FIXME: must verify if atom length < parent atom length */
7538 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7546 qtdemux_tree_get_child_by_index (GNode * node, guint index)
7548 return g_node_nth_child (node, index);
7552 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
7553 GstByteReader * parser)
7557 guint32 child_fourcc, child_len;
7559 for (child = g_node_next_sibling (node); child;
7560 child = g_node_next_sibling (child)) {
7561 buffer = (guint8 *) child->data;
7563 child_fourcc = QT_FOURCC (buffer + 4);
7565 if (child_fourcc == fourcc) {
7567 child_len = QT_UINT32 (buffer);
7568 if (G_UNLIKELY (child_len < (4 + 4)))
7570 /* FIXME: must verify if atom length < parent atom length */
7571 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7580 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
7582 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
7586 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
7588 /* FIXME: This can only reliably work if demuxers have a
7589 * separate streaming thread per srcpad. This should be
7590 * done in a demuxer base class, which integrates parts
7593 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
7598 query = gst_query_new_allocation (stream->caps, FALSE);
7600 if (!gst_pad_peer_query (stream->pad, query)) {
7601 /* not a problem, just debug a little */
7602 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
7605 if (stream->allocator)
7606 gst_object_unref (stream->allocator);
7608 if (gst_query_get_n_allocation_params (query) > 0) {
7609 /* try the allocator */
7610 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
7612 stream->use_allocator = TRUE;
7614 stream->allocator = NULL;
7615 gst_allocation_params_init (&stream->params);
7616 stream->use_allocator = FALSE;
7618 gst_query_unref (query);
7623 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
7624 QtDemuxStream * stream)
7627 const gchar *selected_system;
7629 g_return_val_if_fail (qtdemux != NULL, FALSE);
7630 g_return_val_if_fail (stream != NULL, FALSE);
7631 g_return_val_if_fail (gst_caps_get_size (stream->caps) == 1, FALSE);
7633 if (stream->protection_scheme_type != FOURCC_cenc) {
7634 GST_ERROR_OBJECT (qtdemux, "unsupported protection scheme");
7637 if (qtdemux->protection_system_ids == NULL) {
7638 GST_ERROR_OBJECT (qtdemux, "stream is protected using cenc, but no "
7639 "cenc protection system information has been found");
7642 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
7643 selected_system = gst_protection_select_system ((const gchar **)
7644 qtdemux->protection_system_ids->pdata);
7645 g_ptr_array_remove_index (qtdemux->protection_system_ids,
7646 qtdemux->protection_system_ids->len - 1);
7647 if (!selected_system) {
7648 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
7649 "suitable decryptor element has been found");
7653 s = gst_caps_get_structure (stream->caps, 0);
7654 if (!gst_structure_has_name (s, "application/x-cenc")) {
7655 gst_structure_set (s,
7656 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
7657 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
7659 gst_structure_set_name (s, "application/x-cenc");
7665 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
7667 if (stream->subtype == FOURCC_vide) {
7668 /* fps is calculated base on the duration of the average framerate since
7669 * qt does not have a fixed framerate. */
7670 gboolean fps_available = TRUE;
7672 if ((stream->n_samples == 1) && (stream->first_duration == 0)) {
7677 if (stream->duration == 0 || stream->n_samples < 2) {
7678 stream->fps_n = stream->timescale;
7680 fps_available = FALSE;
7682 GstClockTime avg_duration;
7686 /* duration and n_samples can be updated for fragmented format
7687 * so, framerate of fragmented format is calculated using data in a moof */
7688 if (qtdemux->fragmented && stream->n_samples_moof > 0
7689 && stream->duration_moof > 0) {
7690 n_samples = stream->n_samples_moof;
7691 duration = stream->duration_moof;
7693 n_samples = stream->n_samples;
7694 duration = stream->duration;
7697 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
7698 /* stream->duration is guint64, timescale, n_samples are guint32 */
7700 gst_util_uint64_scale_round (duration -
7701 stream->first_duration, GST_SECOND,
7702 (guint64) (stream->timescale) * (n_samples - 1));
7704 GST_LOG_OBJECT (qtdemux,
7705 "Calculating avg sample duration based on stream (or moof) duration %"
7707 " minus first sample %u, leaving %d samples gives %"
7708 GST_TIME_FORMAT, duration, stream->first_duration,
7709 n_samples - 1, GST_TIME_ARGS (avg_duration));
7711 gst_video_guess_framerate (avg_duration, &stream->fps_n,
7714 GST_DEBUG_OBJECT (qtdemux,
7715 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
7716 stream->timescale, stream->fps_n, stream->fps_d);
7721 stream->caps = gst_caps_make_writable (stream->caps);
7723 gst_caps_set_simple (stream->caps,
7724 "width", G_TYPE_INT, stream->width,
7725 "height", G_TYPE_INT, stream->height, NULL);
7727 /* set framerate if calculated framerate is reliable */
7728 if (fps_available) {
7729 gst_caps_set_simple (stream->caps,
7730 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
7733 /* calculate pixel-aspect-ratio using display width and height */
7734 GST_DEBUG_OBJECT (qtdemux,
7735 "video size %dx%d, target display size %dx%d", stream->width,
7736 stream->height, stream->display_width, stream->display_height);
7737 /* qt file might have pasp atom */
7738 if (stream->par_w > 0 && stream->par_h > 0) {
7739 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
7740 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
7741 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
7742 } else if (stream->display_width > 0 && stream->display_height > 0 &&
7743 stream->width > 0 && stream->height > 0) {
7746 /* calculate the pixel aspect ratio using the display and pixel w/h */
7747 n = stream->display_width * stream->height;
7748 d = stream->display_height * stream->width;
7751 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
7754 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
7755 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
7758 if (stream->interlace_mode > 0) {
7759 if (stream->interlace_mode == 1) {
7760 gst_caps_set_simple (stream->caps, "interlace-mode", G_TYPE_STRING,
7761 "progressive", NULL);
7762 } else if (stream->interlace_mode == 2) {
7763 gst_caps_set_simple (stream->caps, "interlace-mode", G_TYPE_STRING,
7764 "interleaved", NULL);
7765 if (stream->field_order == 9) {
7766 gst_caps_set_simple (stream->caps, "field-order", G_TYPE_STRING,
7767 "top-field-first", NULL);
7768 } else if (stream->field_order == 14) {
7769 gst_caps_set_simple (stream->caps, "field-order", G_TYPE_STRING,
7770 "bottom-field-first", NULL);
7775 /* Create incomplete colorimetry here if needed */
7776 if (stream->colorimetry.range ||
7777 stream->colorimetry.matrix ||
7778 stream->colorimetry.transfer || stream->colorimetry.primaries) {
7779 gchar *colorimetry =
7780 gst_video_colorimetry_to_string (&stream->colorimetry);
7781 gst_caps_set_simple (stream->caps, "colorimetry", G_TYPE_STRING,
7783 g_free (colorimetry);
7786 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
7787 guint par_w = 1, par_h = 1;
7789 if (stream->par_w > 0 && stream->par_h > 0) {
7790 par_w = stream->par_w;
7791 par_h = stream->par_h;
7794 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
7795 stream->width, stream->height, par_w, par_h)) {
7796 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
7799 gst_caps_set_simple (stream->caps,
7800 "multiview-mode", G_TYPE_STRING,
7801 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
7802 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
7803 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
7808 else if (stream->subtype == FOURCC_soun) {
7810 stream->caps = gst_caps_make_writable (stream->caps);
7811 if (stream->rate > 0)
7812 gst_caps_set_simple (stream->caps,
7813 "rate", G_TYPE_INT, (int) stream->rate, NULL);
7814 if (stream->n_channels > 0)
7815 gst_caps_set_simple (stream->caps,
7816 "channels", G_TYPE_INT, stream->n_channels, NULL);
7817 if (stream->n_channels > 2) {
7818 /* FIXME: Need to parse the 'chan' atom to get channel layouts
7819 * correctly; this is just the minimum we can do - assume
7820 * we don't actually have any channel positions. */
7821 gst_caps_set_simple (stream->caps,
7822 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
7828 GstCaps *prev_caps = NULL;
7830 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
7831 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
7832 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
7833 gst_pad_set_active (stream->pad, TRUE);
7835 gst_pad_use_fixed_caps (stream->pad);
7837 if (stream->protected) {
7838 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
7839 GST_ERROR_OBJECT (qtdemux,
7840 "Failed to configure protected stream caps.");
7845 if (stream->new_stream) {
7848 GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
7851 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
7854 gst_event_parse_stream_flags (event, &stream_flags);
7855 if (gst_event_parse_group_id (event, &qtdemux->group_id))
7856 qtdemux->have_group_id = TRUE;
7858 qtdemux->have_group_id = FALSE;
7859 gst_event_unref (event);
7860 } else if (!qtdemux->have_group_id) {
7861 qtdemux->have_group_id = TRUE;
7862 qtdemux->group_id = gst_util_group_id_next ();
7865 stream->new_stream = FALSE;
7867 gst_pad_create_stream_id_printf (stream->pad,
7868 GST_ELEMENT_CAST (qtdemux), "%03u", stream->track_id);
7869 event = gst_event_new_stream_start (stream_id);
7870 if (qtdemux->have_group_id)
7871 gst_event_set_group_id (event, qtdemux->group_id);
7872 if (stream->disabled)
7873 stream_flags |= GST_STREAM_FLAG_UNSELECT;
7874 if (stream->sparse) {
7875 stream_flags |= GST_STREAM_FLAG_SPARSE;
7877 stream_flags &= ~GST_STREAM_FLAG_SPARSE;
7879 gst_event_set_stream_flags (event, stream_flags);
7880 gst_pad_push_event (stream->pad, event);
7884 prev_caps = gst_pad_get_current_caps (stream->pad);
7887 if (!prev_caps || !gst_caps_is_equal_fixed (prev_caps, stream->caps)) {
7888 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
7890 gst_pad_set_caps (stream->pad, stream->caps);
7892 GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
7895 GST_WARNING_OBJECT (qtdemux, "stream without caps");
7899 gst_caps_unref (prev_caps);
7900 stream->new_caps = FALSE;
7906 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
7907 QtDemuxStream * stream, GstTagList * list)
7909 gboolean ret = TRUE;
7910 /* consistent default for push based mode */
7911 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
7913 if (stream->subtype == FOURCC_vide) {
7914 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
7917 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
7920 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7921 gst_object_unref (stream->pad);
7927 qtdemux->n_video_streams++;
7928 } else if (stream->subtype == FOURCC_soun) {
7929 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
7932 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
7934 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7935 gst_object_unref (stream->pad);
7940 qtdemux->n_audio_streams++;
7941 } else if (stream->subtype == FOURCC_strm) {
7942 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
7943 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
7944 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
7945 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
7948 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
7950 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7951 gst_object_unref (stream->pad);
7956 qtdemux->n_sub_streams++;
7957 } else if (stream->caps) {
7958 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
7961 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
7963 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7964 gst_object_unref (stream->pad);
7969 qtdemux->n_video_streams++;
7971 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
7978 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
7979 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
7980 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
7981 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
7983 if (stream->stream_tags)
7984 gst_tag_list_unref (stream->stream_tags);
7985 stream->stream_tags = list;
7987 /* global tags go on each pad anyway */
7988 stream->send_global_tags = TRUE;
7989 /* send upstream GST_EVENT_PROTECTION events that were received before
7990 this source pad was created */
7991 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
7992 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
7996 gst_tag_list_unref (list);
8000 /* find next atom with @fourcc starting at @offset */
8001 static GstFlowReturn
8002 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
8003 guint64 * length, guint32 fourcc)
8009 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
8010 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
8016 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
8017 if (G_UNLIKELY (ret != GST_FLOW_OK))
8019 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
8022 gst_buffer_unref (buf);
8025 gst_buffer_map (buf, &map, GST_MAP_READ);
8026 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
8027 gst_buffer_unmap (buf, &map);
8028 gst_buffer_unref (buf);
8030 if (G_UNLIKELY (*length == 0)) {
8031 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
8032 ret = GST_FLOW_ERROR;
8036 if (lfourcc == fourcc) {
8037 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
8041 GST_LOG_OBJECT (qtdemux,
8042 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
8043 GST_FOURCC_ARGS (fourcc), *offset);
8052 /* might simply have had last one */
8053 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
8058 /* should only do something in pull mode */
8059 /* call with OBJECT lock */
8060 static GstFlowReturn
8061 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
8063 guint64 length, offset;
8064 GstBuffer *buf = NULL;
8065 GstFlowReturn ret = GST_FLOW_OK;
8066 GstFlowReturn res = GST_FLOW_OK;
8069 offset = qtdemux->moof_offset;
8070 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
8073 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8074 return GST_FLOW_EOS;
8077 /* best not do pull etc with lock held */
8078 GST_OBJECT_UNLOCK (qtdemux);
8080 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8081 if (ret != GST_FLOW_OK)
8084 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
8085 if (G_UNLIKELY (ret != GST_FLOW_OK))
8087 gst_buffer_map (buf, &map, GST_MAP_READ);
8088 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
8089 gst_buffer_unmap (buf, &map);
8090 gst_buffer_unref (buf);
8095 gst_buffer_unmap (buf, &map);
8096 gst_buffer_unref (buf);
8100 /* look for next moof */
8101 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8102 if (G_UNLIKELY (ret != GST_FLOW_OK))
8106 GST_OBJECT_LOCK (qtdemux);
8108 qtdemux->moof_offset = offset;
8114 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
8116 res = GST_FLOW_ERROR;
8121 /* maybe upstream temporarily flushing */
8122 if (ret != GST_FLOW_FLUSHING) {
8123 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8126 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
8127 /* resume at current position next time */
8134 /* initialise bytereaders for stbl sub-atoms */
8136 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
8138 stream->stbl_index = -1; /* no samples have yet been parsed */
8139 stream->sample_index = -1;
8141 /* time-to-sample atom */
8142 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
8145 /* copy atom data into a new buffer for later use */
8146 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
8148 /* skip version + flags */
8149 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
8150 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
8152 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
8154 /* make sure there's enough data */
8155 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
8156 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
8157 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
8158 stream->n_sample_times);
8159 if (!stream->n_sample_times)
8163 /* sync sample atom */
8164 stream->stps_present = FALSE;
8165 if ((stream->stss_present =
8166 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
8167 &stream->stss) ? TRUE : FALSE) == TRUE) {
8168 /* copy atom data into a new buffer for later use */
8169 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
8171 /* skip version + flags */
8172 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
8173 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
8176 if (stream->n_sample_syncs) {
8177 /* make sure there's enough data */
8178 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
8182 /* partial sync sample atom */
8183 if ((stream->stps_present =
8184 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
8185 &stream->stps) ? TRUE : FALSE) == TRUE) {
8186 /* copy atom data into a new buffer for later use */
8187 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
8189 /* skip version + flags */
8190 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
8191 !gst_byte_reader_get_uint32_be (&stream->stps,
8192 &stream->n_sample_partial_syncs))
8195 /* if there are no entries, the stss table contains the real
8197 if (stream->n_sample_partial_syncs) {
8198 /* make sure there's enough data */
8199 if (!qt_atom_parser_has_chunks (&stream->stps,
8200 stream->n_sample_partial_syncs, 4))
8207 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
8210 /* copy atom data into a new buffer for later use */
8211 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
8213 /* skip version + flags */
8214 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
8215 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
8218 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
8221 if (!stream->n_samples)
8224 /* sample-to-chunk atom */
8225 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
8228 /* copy atom data into a new buffer for later use */
8229 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
8231 /* skip version + flags */
8232 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
8233 !gst_byte_reader_get_uint32_be (&stream->stsc,
8234 &stream->n_samples_per_chunk))
8237 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
8238 stream->n_samples_per_chunk);
8240 /* make sure there's enough data */
8241 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
8247 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
8248 stream->co_size = sizeof (guint32);
8249 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
8251 stream->co_size = sizeof (guint64);
8255 /* copy atom data into a new buffer for later use */
8256 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
8258 /* skip version + flags */
8259 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
8262 /* chunks_are_samples == TRUE means treat chunks as samples */
8263 stream->chunks_are_samples = stream->sample_size && !stream->sampled;
8264 if (stream->chunks_are_samples) {
8265 /* treat chunks as samples */
8266 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
8269 /* skip number of entries */
8270 if (!gst_byte_reader_skip (&stream->stco, 4))
8273 /* make sure there are enough data in the stsz atom */
8274 if (!stream->sample_size) {
8275 /* different sizes for each sample */
8276 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
8281 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
8282 stream->n_samples, (guint) sizeof (QtDemuxSample),
8283 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
8285 if (stream->n_samples >=
8286 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
8287 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
8288 "be larger than %uMB (broken file?)", stream->n_samples,
8289 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
8293 g_assert (stream->samples == NULL);
8294 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
8295 if (!stream->samples) {
8296 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
8301 /* composition time-to-sample */
8302 if ((stream->ctts_present =
8303 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
8304 &stream->ctts) ? TRUE : FALSE) == TRUE) {
8305 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
8307 /* copy atom data into a new buffer for later use */
8308 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
8310 /* skip version + flags */
8311 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
8312 || !gst_byte_reader_get_uint32_be (&stream->ctts,
8313 &stream->n_composition_times))
8316 /* make sure there's enough data */
8317 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
8321 /* This is optional, if missing we iterate the ctts */
8322 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
8323 if (!gst_byte_reader_skip (&cslg, 1 + 3)
8324 || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
8325 g_free ((gpointer) cslg.data);
8329 gint32 cslg_least = 0;
8330 guint num_entries, pos;
8333 pos = gst_byte_reader_get_pos (&stream->ctts);
8334 num_entries = stream->n_composition_times;
8336 stream->cslg_shift = 0;
8338 for (i = 0; i < num_entries; i++) {
8341 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
8342 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8344 if (offset < cslg_least)
8345 cslg_least = offset;
8349 stream->cslg_shift = ABS (cslg_least);
8351 stream->cslg_shift = 0;
8353 /* reset the reader so we can generate sample table */
8354 gst_byte_reader_set_pos (&stream->ctts, pos);
8357 /* Ensure the cslg_shift value is consistent so we can use it
8358 * unconditionnally to produce TS and Segment */
8359 stream->cslg_shift = 0;
8366 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8367 (_("This file is corrupt and cannot be played.")), (NULL));
8372 gst_qtdemux_stbl_free (stream);
8373 if (!qtdemux->fragmented) {
8374 /* not quite good */
8375 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
8378 /* may pick up samples elsewhere */
8384 /* collect samples from the next sample to be parsed up to sample @n for @stream
8385 * by reading the info from @stbl
8387 * This code can be executed from both the streaming thread and the seeking
8388 * thread so it takes the object lock to protect itself
8391 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
8394 QtDemuxSample *samples, *first, *cur, *last;
8395 guint32 n_samples_per_chunk;
8398 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
8399 GST_FOURCC_FORMAT ", pad %s", GST_FOURCC_ARGS (stream->fourcc),
8400 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
8402 n_samples = stream->n_samples;
8405 goto out_of_samples;
8407 GST_OBJECT_LOCK (qtdemux);
8408 if (n <= stream->stbl_index)
8409 goto already_parsed;
8411 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
8413 if (!stream->stsz.data) {
8414 /* so we already parsed and passed all the moov samples;
8415 * onto fragmented ones */
8416 g_assert (qtdemux->fragmented);
8420 /* pointer to the sample table */
8421 samples = stream->samples;
8423 /* starts from -1, moves to the next sample index to parse */
8424 stream->stbl_index++;
8426 /* keep track of the first and last sample to fill */
8427 first = &samples[stream->stbl_index];
8430 if (!stream->chunks_are_samples) {
8431 /* set the sample sizes */
8432 if (stream->sample_size == 0) {
8433 /* different sizes for each sample */
8434 for (cur = first; cur <= last; cur++) {
8435 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
8436 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
8437 (guint) (cur - samples), cur->size);
8440 /* samples have the same size */
8441 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
8442 for (cur = first; cur <= last; cur++)
8443 cur->size = stream->sample_size;
8447 n_samples_per_chunk = stream->n_samples_per_chunk;
8450 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
8453 if (stream->stsc_chunk_index >= stream->last_chunk
8454 || stream->stsc_chunk_index < stream->first_chunk) {
8455 stream->first_chunk =
8456 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8457 stream->samples_per_chunk =
8458 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8459 gst_byte_reader_skip_unchecked (&stream->stsc, 4);
8461 /* chunk numbers are counted from 1 it seems */
8462 if (G_UNLIKELY (stream->first_chunk == 0))
8465 --stream->first_chunk;
8467 /* the last chunk of each entry is calculated by taking the first chunk
8468 * of the next entry; except if there is no next, where we fake it with
8470 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
8471 stream->last_chunk = G_MAXUINT32;
8473 stream->last_chunk =
8474 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
8475 if (G_UNLIKELY (stream->last_chunk == 0))
8478 --stream->last_chunk;
8481 GST_LOG_OBJECT (qtdemux,
8482 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
8483 stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
8485 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
8488 if (stream->last_chunk != G_MAXUINT32) {
8489 if (!qt_atom_parser_peek_sub (&stream->stco,
8490 stream->first_chunk * stream->co_size,
8491 (stream->last_chunk - stream->first_chunk) * stream->co_size,
8496 stream->co_chunk = stream->stco;
8497 if (!gst_byte_reader_skip (&stream->co_chunk,
8498 stream->first_chunk * stream->co_size))
8502 stream->stsc_chunk_index = stream->first_chunk;
8505 last_chunk = stream->last_chunk;
8507 if (stream->chunks_are_samples) {
8508 cur = &samples[stream->stsc_chunk_index];
8510 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8513 stream->stsc_chunk_index = j;
8518 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
8521 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
8522 "%" G_GUINT64_FORMAT, j, cur->offset);
8524 if (stream->samples_per_frame > 0 && stream->bytes_per_frame > 0) {
8526 (stream->samples_per_chunk * stream->n_channels) /
8527 stream->samples_per_frame * stream->bytes_per_frame;
8529 cur->size = stream->samples_per_chunk;
8532 GST_DEBUG_OBJECT (qtdemux,
8533 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
8534 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
8535 stream->stco_sample_index)), cur->size);
8537 cur->timestamp = stream->stco_sample_index;
8538 cur->duration = stream->samples_per_chunk;
8539 cur->keyframe = TRUE;
8542 stream->stco_sample_index += stream->samples_per_chunk;
8544 stream->stsc_chunk_index = j;
8546 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8547 guint32 samples_per_chunk;
8548 guint64 chunk_offset;
8550 if (!stream->stsc_sample_index
8551 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
8552 &stream->chunk_offset))
8555 samples_per_chunk = stream->samples_per_chunk;
8556 chunk_offset = stream->chunk_offset;
8558 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
8559 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
8560 G_GUINT64_FORMAT " and size %d",
8561 (guint) (cur - samples), chunk_offset, cur->size);
8563 cur->offset = chunk_offset;
8564 chunk_offset += cur->size;
8567 if (G_UNLIKELY (cur > last)) {
8569 stream->stsc_sample_index = k + 1;
8570 stream->chunk_offset = chunk_offset;
8571 stream->stsc_chunk_index = j;
8575 stream->stsc_sample_index = 0;
8577 stream->stsc_chunk_index = j;
8579 stream->stsc_index++;
8582 if (stream->chunks_are_samples)
8586 guint32 n_sample_times;
8588 n_sample_times = stream->n_sample_times;
8591 for (i = stream->stts_index; i < n_sample_times; i++) {
8592 guint32 stts_samples;
8593 gint32 stts_duration;
8596 if (stream->stts_sample_index >= stream->stts_samples
8597 || !stream->stts_sample_index) {
8599 stream->stts_samples =
8600 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8601 stream->stts_duration =
8602 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8604 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
8605 i, stream->stts_samples, stream->stts_duration);
8607 stream->stts_sample_index = 0;
8610 stts_samples = stream->stts_samples;
8611 stts_duration = stream->stts_duration;
8612 stts_time = stream->stts_time;
8614 for (j = stream->stts_sample_index; j < stts_samples; j++) {
8615 GST_DEBUG_OBJECT (qtdemux,
8616 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
8617 (guint) (cur - samples), j,
8618 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
8620 cur->timestamp = stts_time;
8621 cur->duration = stts_duration;
8623 /* avoid 32-bit wrap-around,
8624 * but still mind possible 'negative' duration */
8625 stts_time += (gint64) stts_duration;
8628 if (G_UNLIKELY (cur > last)) {
8630 stream->stts_time = stts_time;
8631 stream->stts_sample_index = j + 1;
8632 if (stream->stts_sample_index >= stream->stts_samples)
8633 stream->stts_index++;
8637 stream->stts_sample_index = 0;
8638 stream->stts_time = stts_time;
8639 stream->stts_index++;
8641 /* fill up empty timestamps with the last timestamp, this can happen when
8642 * the last samples do not decode and so we don't have timestamps for them.
8643 * We however look at the last timestamp to estimate the track length so we
8644 * need something in here. */
8645 for (; cur < last; cur++) {
8646 GST_DEBUG_OBJECT (qtdemux,
8647 "fill sample %d: timestamp %" GST_TIME_FORMAT,
8648 (guint) (cur - samples),
8649 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
8650 cur->timestamp = stream->stts_time;
8656 /* sample sync, can be NULL */
8657 if (stream->stss_present == TRUE) {
8658 guint32 n_sample_syncs;
8660 n_sample_syncs = stream->n_sample_syncs;
8662 if (!n_sample_syncs) {
8663 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
8664 stream->all_keyframe = TRUE;
8666 for (i = stream->stss_index; i < n_sample_syncs; i++) {
8667 /* note that the first sample is index 1, not 0 */
8670 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
8672 if (G_LIKELY (index > 0 && index <= n_samples)) {
8674 samples[index].keyframe = TRUE;
8675 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8676 /* and exit if we have enough samples */
8677 if (G_UNLIKELY (index >= n)) {
8684 stream->stss_index = i;
8687 /* stps marks partial sync frames like open GOP I-Frames */
8688 if (stream->stps_present == TRUE) {
8689 guint32 n_sample_partial_syncs;
8691 n_sample_partial_syncs = stream->n_sample_partial_syncs;
8693 /* if there are no entries, the stss table contains the real
8695 if (n_sample_partial_syncs) {
8696 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
8697 /* note that the first sample is index 1, not 0 */
8700 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
8702 if (G_LIKELY (index > 0 && index <= n_samples)) {
8704 samples[index].keyframe = TRUE;
8705 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8706 /* and exit if we have enough samples */
8707 if (G_UNLIKELY (index >= n)) {
8714 stream->stps_index = i;
8718 /* no stss, all samples are keyframes */
8719 stream->all_keyframe = TRUE;
8720 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
8725 /* composition time to sample */
8726 if (stream->ctts_present == TRUE) {
8727 guint32 n_composition_times;
8729 gint32 ctts_soffset;
8731 /* Fill in the pts_offsets */
8733 n_composition_times = stream->n_composition_times;
8735 for (i = stream->ctts_index; i < n_composition_times; i++) {
8736 if (stream->ctts_sample_index >= stream->ctts_count
8737 || !stream->ctts_sample_index) {
8738 stream->ctts_count =
8739 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
8740 stream->ctts_soffset =
8741 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8742 stream->ctts_sample_index = 0;
8745 ctts_count = stream->ctts_count;
8746 ctts_soffset = stream->ctts_soffset;
8748 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
8749 cur->pts_offset = ctts_soffset;
8752 if (G_UNLIKELY (cur > last)) {
8754 stream->ctts_sample_index = j + 1;
8758 stream->ctts_sample_index = 0;
8759 stream->ctts_index++;
8763 stream->stbl_index = n;
8764 /* if index has been completely parsed, free data that is no-longer needed */
8765 if (n + 1 == stream->n_samples) {
8766 gst_qtdemux_stbl_free (stream);
8767 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
8768 if (qtdemux->pullbased) {
8769 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
8770 while (n + 1 == stream->n_samples)
8771 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
8775 GST_OBJECT_UNLOCK (qtdemux);
8782 GST_LOG_OBJECT (qtdemux,
8783 "Tried to parse up to sample %u but this sample has already been parsed",
8785 /* if fragmented, there may be more */
8786 if (qtdemux->fragmented && n == stream->stbl_index)
8788 GST_OBJECT_UNLOCK (qtdemux);
8794 GST_LOG_OBJECT (qtdemux,
8795 "Tried to parse up to sample %u but there are only %u samples", n + 1,
8797 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8798 (_("This file is corrupt and cannot be played.")), (NULL));
8803 GST_OBJECT_UNLOCK (qtdemux);
8804 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8805 (_("This file is corrupt and cannot be played.")), (NULL));
8810 /* collect all segment info for @stream.
8813 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
8817 /* accept edts if they contain gaps at start and there is only
8818 * one media segment */
8819 gboolean allow_pushbased_edts = TRUE;
8820 gint media_segments_count = 0;
8822 /* parse and prepare segment info from the edit list */
8823 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
8824 stream->n_segments = 0;
8825 stream->segments = NULL;
8826 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
8829 gint i, count, entry_size;
8832 const guint8 *buffer;
8836 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
8837 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
8840 buffer = elst->data;
8842 size = QT_UINT32 (buffer);
8843 /* version, flags, n_segments */
8845 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
8848 version = QT_UINT8 (buffer + 8);
8849 entry_size = (version == 1) ? 20 : 12;
8851 n_segments = QT_UINT32 (buffer + 12);
8853 if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
8854 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
8858 /* we might allocate a bit too much, at least allocate 1 segment */
8859 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
8861 /* segments always start from 0 */
8866 for (i = 0; i < n_segments; i++) {
8869 gboolean time_valid = TRUE;
8870 QtDemuxSegment *segment;
8872 GstClockTime media_start = GST_CLOCK_TIME_NONE;
8875 media_time = QT_UINT64 (buffer + 8);
8876 duration = QT_UINT64 (buffer);
8877 if (media_time == G_MAXUINT64)
8880 media_time = QT_UINT32 (buffer + 4);
8881 duration = QT_UINT32 (buffer);
8882 if (media_time == G_MAXUINT32)
8887 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
8889 segment = &stream->segments[count++];
8891 /* time and duration expressed in global timescale */
8892 segment->time = stime;
8893 /* add non scaled values so we don't cause roundoff errors */
8894 if (duration || media_start == GST_CLOCK_TIME_NONE) {
8896 stime = QTTIME_TO_GSTTIME (qtdemux, time);
8897 segment->duration = stime - segment->time;
8899 /* zero duration does not imply media_start == media_stop
8900 * but, only specify media_start.*/
8901 stime = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
8902 if (GST_CLOCK_TIME_IS_VALID (stime) && time_valid
8903 && stime >= media_start) {
8904 segment->duration = stime - media_start;
8906 segment->duration = GST_CLOCK_TIME_NONE;
8909 segment->stop_time = stime;
8911 segment->trak_media_start = media_time;
8912 /* media_time expressed in stream timescale */
8914 segment->media_start = media_start;
8915 segment->media_stop = segment->media_start + segment->duration;
8916 media_segments_count++;
8918 segment->media_start = GST_CLOCK_TIME_NONE;
8919 segment->media_stop = GST_CLOCK_TIME_NONE;
8921 rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
8923 if (rate_int <= 1) {
8924 /* 0 is not allowed, some programs write 1 instead of the floating point
8926 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
8930 segment->rate = rate_int / 65536.0;
8933 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
8934 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
8935 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
8936 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
8937 i, GST_TIME_ARGS (segment->time),
8938 GST_TIME_ARGS (segment->duration),
8939 GST_TIME_ARGS (segment->media_start), media_time,
8940 GST_TIME_ARGS (segment->media_stop),
8941 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
8943 if (segment->stop_time > qtdemux->segment.stop) {
8944 GST_WARNING_OBJECT (qtdemux, "Segment %d "
8945 " extends to %" GST_TIME_FORMAT
8946 " past the end of the file duration %" GST_TIME_FORMAT
8947 " it will be truncated", i, GST_TIME_ARGS (segment->stop_time),
8948 GST_TIME_ARGS (qtdemux->segment.stop));
8949 qtdemux->segment.stop = segment->stop_time;
8952 buffer += entry_size;
8954 GST_DEBUG_OBJECT (qtdemux, "found %d segments", count);
8955 stream->n_segments = count;
8956 if (media_segments_count != 1)
8957 allow_pushbased_edts = FALSE;
8961 /* push based does not handle segments, so act accordingly here,
8962 * and warn if applicable */
8963 if (!qtdemux->pullbased && !allow_pushbased_edts) {
8964 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
8965 /* remove and use default one below, we stream like it anyway */
8966 g_free (stream->segments);
8967 stream->segments = NULL;
8968 stream->n_segments = 0;
8971 /* no segments, create one to play the complete trak */
8972 if (stream->n_segments == 0) {
8973 GstClockTime stream_duration =
8974 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
8976 if (stream->segments == NULL)
8977 stream->segments = g_new (QtDemuxSegment, 1);
8979 /* represent unknown our way */
8980 if (stream_duration == 0)
8981 stream_duration = GST_CLOCK_TIME_NONE;
8983 stream->segments[0].time = 0;
8984 stream->segments[0].stop_time = stream_duration;
8985 stream->segments[0].duration = stream_duration;
8986 stream->segments[0].media_start = 0;
8987 stream->segments[0].media_stop = stream_duration;
8988 stream->segments[0].rate = 1.0;
8989 stream->segments[0].trak_media_start = 0;
8991 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
8992 GST_TIME_ARGS (stream_duration));
8993 stream->n_segments = 1;
8994 stream->dummy_segment = TRUE;
8996 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
9002 * Parses the stsd atom of a svq3 trak looking for
9003 * the SMI and gama atoms.
9006 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
9007 guint8 ** gamma, GstBuffer ** seqh)
9009 guint8 *_gamma = NULL;
9010 GstBuffer *_seqh = NULL;
9011 guint8 *stsd_data = stsd->data;
9012 guint32 length = QT_UINT32 (stsd_data);
9016 GST_WARNING_OBJECT (qtdemux, "stsd too short");
9022 version = QT_UINT16 (stsd_data);
9027 while (length > 8) {
9028 guint32 fourcc, size;
9030 size = QT_UINT32 (stsd_data);
9031 fourcc = QT_FOURCC (stsd_data + 4);
9032 data = stsd_data + 8;
9035 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
9036 "svq3 atom parsing");
9045 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
9046 " for gama atom, expected 12", size);
9051 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
9053 if (_seqh != NULL) {
9054 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
9055 " found, ignoring");
9057 seqh_size = QT_UINT32 (data + 4);
9058 if (seqh_size > 0) {
9059 _seqh = gst_buffer_new_and_alloc (seqh_size);
9060 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
9067 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
9068 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
9072 if (size <= length) {
9078 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
9081 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
9082 G_GUINT16_FORMAT, version);
9093 gst_buffer_unref (_seqh);
9098 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
9105 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
9106 * atom that might contain a 'data' atom with the rtsp uri.
9107 * This case was reported in bug #597497, some info about
9108 * the hndl atom can be found in TN1195
9110 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
9111 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
9114 guint32 dref_num_entries = 0;
9115 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
9116 gst_byte_reader_skip (&dref, 4) &&
9117 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
9120 /* search dref entries for hndl atom */
9121 for (i = 0; i < dref_num_entries; i++) {
9122 guint32 size = 0, type;
9123 guint8 string_len = 0;
9124 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
9125 qt_atom_parser_get_fourcc (&dref, &type)) {
9126 if (type == FOURCC_hndl) {
9127 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
9129 /* skip data reference handle bytes and the
9130 * following pascal string and some extra 4
9131 * bytes I have no idea what are */
9132 if (!gst_byte_reader_skip (&dref, 4) ||
9133 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
9134 !gst_byte_reader_skip (&dref, string_len + 4)) {
9135 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
9139 /* iterate over the atoms to find the data atom */
9140 while (gst_byte_reader_get_remaining (&dref) >= 8) {
9144 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
9145 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
9146 if (atom_type == FOURCC_data) {
9147 const guint8 *uri_aux = NULL;
9149 /* found the data atom that might contain the rtsp uri */
9150 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
9151 "hndl atom, interpreting it as an URI");
9152 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
9154 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
9155 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
9157 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
9158 "didn't contain a rtsp address");
9160 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
9165 /* skipping to the next entry */
9166 if (!gst_byte_reader_skip (&dref, atom_size - 8))
9169 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
9176 /* skip to the next entry */
9177 if (!gst_byte_reader_skip (&dref, size - 8))
9180 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
9183 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
9189 #define AMR_NB_ALL_MODES 0x81ff
9190 #define AMR_WB_ALL_MODES 0x83ff
9192 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
9194 /* The 'damr' atom is of the form:
9196 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
9197 * 32 b 8 b 16 b 8 b 8 b
9199 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
9200 * represents the highest mode used in the stream (and thus the maximum
9201 * bitrate), with a couple of special cases as seen below.
9204 /* Map of frame type ID -> bitrate */
9205 static const guint nb_bitrates[] = {
9206 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
9208 static const guint wb_bitrates[] = {
9209 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
9215 gst_buffer_map (buf, &map, GST_MAP_READ);
9217 if (map.size != 0x11) {
9218 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
9222 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
9223 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
9224 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
9228 mode_set = QT_UINT16 (map.data + 13);
9230 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
9231 max_mode = 7 + (wb ? 1 : 0);
9233 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
9234 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
9236 if (max_mode == -1) {
9237 GST_DEBUG ("No mode indication was found (mode set) = %x",
9242 gst_buffer_unmap (buf, &map);
9243 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
9246 gst_buffer_unmap (buf, &map);
9251 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
9252 GstByteReader * reader, guint32 * matrix, const gchar * atom)
9255 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
9261 if (gst_byte_reader_get_remaining (reader) < 36)
9264 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
9265 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
9266 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
9267 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
9268 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
9269 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
9270 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
9271 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
9272 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
9274 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
9275 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
9276 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
9278 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
9279 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
9281 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
9282 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
9289 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
9290 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
9297 * This macro will only compare value abdegh, it expects cfi to have already
9300 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
9301 (m)[3] == (d << 16) && (m)[4] == (e << 16))
9303 /* only handle the cases where the last column has standard values */
9304 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
9305 const gchar *rotation_tag = NULL;
9307 /* no rotation needed */
9308 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
9310 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
9311 rotation_tag = "rotate-90";
9312 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
9313 rotation_tag = "rotate-180";
9314 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
9315 rotation_tag = "rotate-270";
9317 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9320 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
9322 if (rotation_tag != NULL) {
9323 if (*taglist == NULL)
9324 *taglist = gst_tag_list_new_empty ();
9325 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
9326 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
9329 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9333 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
9334 * protected streams (sinf, frma, schm and schi); if the protection scheme is
9335 * Common Encryption (cenc), the function will also parse the tenc box (defined
9336 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
9337 * (typically an enc[v|a|t|s] sample entry); the function will set
9338 * @original_fmt to the fourcc of the original unencrypted stream format.
9339 * Returns TRUE if successful; FALSE otherwise. */
9341 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
9342 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
9349 g_return_val_if_fail (qtdemux != NULL, FALSE);
9350 g_return_val_if_fail (stream != NULL, FALSE);
9351 g_return_val_if_fail (container != NULL, FALSE);
9352 g_return_val_if_fail (original_fmt != NULL, FALSE);
9354 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
9355 if (G_UNLIKELY (!sinf)) {
9356 if (stream->protection_scheme_type == FOURCC_cenc) {
9357 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
9358 "mandatory for Common Encryption");
9364 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
9365 if (G_UNLIKELY (!frma)) {
9366 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
9370 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
9371 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
9372 GST_FOURCC_ARGS (*original_fmt));
9374 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
9376 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
9379 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
9380 stream->protection_scheme_version =
9381 QT_UINT32 ((const guint8 *) schm->data + 16);
9383 GST_DEBUG_OBJECT (qtdemux,
9384 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
9385 "protection_scheme_version: %#010x",
9386 GST_FOURCC_ARGS (stream->protection_scheme_type),
9387 stream->protection_scheme_version);
9389 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
9391 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
9394 if (stream->protection_scheme_type == FOURCC_cenc) {
9395 QtDemuxCencSampleSetInfo *info;
9397 const guint8 *tenc_data;
9398 guint32 isEncrypted;
9400 const guint8 *default_kid;
9403 if (G_UNLIKELY (!stream->protection_scheme_info))
9404 stream->protection_scheme_info =
9405 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
9407 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
9409 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
9411 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
9412 "which is mandatory for Common Encryption");
9415 tenc_data = (const guint8 *) tenc->data + 12;
9416 isEncrypted = QT_UINT24 (tenc_data);
9417 iv_size = QT_UINT8 (tenc_data + 3);
9418 default_kid = (tenc_data + 4);
9419 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
9420 gst_buffer_fill (kid_buf, 0, default_kid, 16);
9421 if (info->default_properties)
9422 gst_structure_free (info->default_properties);
9423 info->default_properties =
9424 gst_structure_new ("application/x-cenc",
9425 "iv_size", G_TYPE_UINT, iv_size,
9426 "encrypted", G_TYPE_BOOLEAN, (isEncrypted == 1),
9427 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
9428 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
9429 "is_encrypted=%u, iv_size=%u", isEncrypted, iv_size);
9430 gst_buffer_unref (kid_buf);
9436 * With each track we associate a new QtDemuxStream that contains all the info
9438 * traks that do not decode to something (like strm traks) will not have a pad.
9441 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
9462 QtDemuxStream *stream = NULL;
9463 gboolean new_stream = FALSE;
9464 gchar *codec = NULL;
9465 const guint8 *stsd_data;
9466 guint16 lang_code; /* quicktime lang code or packed iso code */
9468 guint32 tkhd_flags = 0;
9469 guint8 tkhd_version = 0;
9471 guint value_size, stsd_len, len;
9475 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
9477 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
9478 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
9479 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
9482 /* pick between 64 or 32 bits */
9483 value_size = tkhd_version == 1 ? 8 : 4;
9484 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
9485 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
9488 if (!qtdemux->got_moov) {
9489 if (qtdemux_find_stream (qtdemux, track_id))
9490 goto existing_stream;
9491 stream = _create_stream ();
9492 stream->track_id = track_id;
9495 stream = qtdemux_find_stream (qtdemux, track_id);
9497 GST_WARNING_OBJECT (qtdemux, "Stream not found, going to ignore it");
9501 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
9503 /* flush samples data from this track from previous moov */
9504 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
9505 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
9507 /* need defaults for fragments */
9508 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
9510 if ((tkhd_flags & 1) == 0)
9511 stream->disabled = TRUE;
9513 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
9514 tkhd_version, tkhd_flags, stream->track_id);
9516 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
9519 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
9520 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
9521 if (qtdemux->major_brand != FOURCC_mjp2 ||
9522 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
9526 len = QT_UINT32 ((guint8 *) mdhd->data);
9527 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
9528 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
9529 if (version == 0x01000000) {
9532 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
9533 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
9534 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
9538 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
9539 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
9540 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
9543 if (lang_code < 0x400) {
9544 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
9545 } else if (lang_code == 0x7fff) {
9546 stream->lang_id[0] = 0; /* unspecified */
9548 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
9549 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
9550 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
9551 stream->lang_id[3] = 0;
9554 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
9556 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
9558 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
9559 lang_code, stream->lang_id);
9561 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
9564 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
9565 /* chapters track reference */
9566 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
9568 gsize length = GST_READ_UINT32_BE (chap->data);
9569 if (qtdemux->chapters_track_id)
9570 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
9573 qtdemux->chapters_track_id =
9574 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
9579 /* fragmented files may have bogus duration in moov */
9580 if (!qtdemux->fragmented &&
9581 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
9582 guint64 tdur1, tdur2;
9584 /* don't overflow */
9585 tdur1 = stream->timescale * (guint64) qtdemux->duration;
9586 tdur2 = qtdemux->timescale * (guint64) stream->duration;
9589 * some of those trailers, nowadays, have prologue images that are
9590 * themselves video tracks as well. I haven't really found a way to
9591 * identify those yet, except for just looking at their duration. */
9592 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
9593 GST_WARNING_OBJECT (qtdemux,
9594 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
9595 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
9596 "found, assuming preview image or something; skipping track",
9597 stream->duration, stream->timescale, qtdemux->duration,
9598 qtdemux->timescale);
9600 gst_qtdemux_stream_free (qtdemux, stream);
9605 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
9608 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
9609 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
9611 len = QT_UINT32 ((guint8 *) hdlr->data);
9613 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
9614 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
9615 GST_FOURCC_ARGS (stream->subtype));
9617 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
9620 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
9623 /*parse svmi header if existing */
9624 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
9626 len = QT_UINT32 ((guint8 *) svmi->data);
9627 version = QT_UINT32 ((guint8 *) svmi->data + 8);
9629 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
9630 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
9631 guint8 frame_type, frame_layout;
9633 /* MPEG-A stereo video */
9634 if (qtdemux->major_brand == FOURCC_ss02)
9635 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
9637 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
9638 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
9639 switch (frame_type) {
9641 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
9644 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
9647 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
9650 /* mode 3 is primary/secondary view sequence, ie
9651 * left/right views in separate tracks. See section 7.2
9652 * of ISO/IEC 23000-11:2009 */
9653 GST_FIXME_OBJECT (qtdemux,
9654 "Implement stereo video in separate streams");
9657 if ((frame_layout & 0x1) == 0)
9658 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
9660 GST_LOG_OBJECT (qtdemux,
9661 "StereoVideo: composition type: %u, is_left_first: %u",
9662 frame_type, frame_layout);
9663 stream->multiview_mode = mode;
9664 stream->multiview_flags = flags;
9669 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
9671 stsd_data = (const guint8 *) stsd->data;
9673 /* stsd should at least have one entry */
9674 stsd_len = QT_UINT32 (stsd_data);
9675 if (stsd_len < 24) {
9676 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
9677 if (stream->subtype == FOURCC_vivo) {
9679 gst_qtdemux_stream_free (qtdemux, stream);
9686 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
9688 /* and that entry should fit within stsd */
9689 len = QT_UINT32 (stsd_data + 16);
9690 if (len > stsd_len + 16)
9693 stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
9694 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
9695 GST_FOURCC_ARGS (stream->fourcc));
9696 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
9698 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
9699 goto error_encrypted;
9701 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
9702 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
9703 stream->protected = TRUE;
9704 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
9705 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
9708 if (stream->subtype == FOURCC_vide) {
9709 guint32 w = 0, h = 0;
9711 gint depth, palette_size, palette_count;
9713 guint32 *palette_data = NULL;
9715 stream->sampled = TRUE;
9717 /* version 1 uses some 64-bit ints */
9718 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
9721 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
9724 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
9725 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
9728 stream->display_width = w >> 16;
9729 stream->display_height = h >> 16;
9731 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
9732 &stream->stream_tags);
9738 stream->width = QT_UINT16 (stsd_data + offset + 32);
9739 stream->height = QT_UINT16 (stsd_data + offset + 34);
9740 stream->fps_n = 0; /* this is filled in later */
9741 stream->fps_d = 0; /* this is filled in later */
9742 stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
9743 stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
9745 /* if color_table_id is 0, ctab atom must follow; however some files
9746 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
9747 * if color table is not present we'll correct the value */
9748 if (stream->color_table_id == 0 &&
9749 (len < 90 || QT_FOURCC (stsd_data + offset + 86) != FOURCC_ctab)) {
9750 stream->color_table_id = -1;
9753 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
9754 stream->width, stream->height, stream->bits_per_sample,
9755 stream->color_table_id);
9757 depth = stream->bits_per_sample;
9759 /* more than 32 bits means grayscale */
9760 gray = (depth > 32);
9761 /* low 32 bits specify the depth */
9764 /* different number of palette entries is determined by depth. */
9766 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
9767 palette_count = (1 << depth);
9768 palette_size = palette_count * 4;
9770 if (stream->color_table_id) {
9771 switch (palette_count) {
9775 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
9778 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
9782 palette_data = g_memdup (ff_qt_grayscale_palette_16, palette_size);
9784 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
9788 palette_data = g_memdup (ff_qt_grayscale_palette_256, palette_size);
9790 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
9793 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
9794 (_("The video in this file might not play correctly.")),
9795 ("unsupported palette depth %d", depth));
9799 gint i, j, start, end;
9805 start = QT_UINT32 (stsd_data + offset + 86);
9806 palette_count = QT_UINT16 (stsd_data + offset + 90);
9807 end = QT_UINT16 (stsd_data + offset + 92);
9809 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
9810 start, end, palette_count);
9817 if (len < 94 + (end - start) * 8)
9820 /* palette is always the same size */
9821 palette_data = g_malloc0 (256 * 4);
9822 palette_size = 256 * 4;
9824 for (j = 0, i = start; i <= end; j++, i++) {
9827 a = QT_UINT16 (stsd_data + offset + 94 + (j * 8));
9828 r = QT_UINT16 (stsd_data + offset + 96 + (j * 8));
9829 g = QT_UINT16 (stsd_data + offset + 98 + (j * 8));
9830 b = QT_UINT16 (stsd_data + offset + 100 + (j * 8));
9832 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
9833 (g & 0xff00) | (b >> 8);
9838 gst_caps_unref (stream->caps);
9841 qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
9842 if (G_UNLIKELY (!stream->caps)) {
9843 g_free (palette_data);
9844 goto unknown_stream;
9848 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
9849 GST_TAG_VIDEO_CODEC, codec, NULL);
9858 if (stream->rgb8_palette)
9859 gst_memory_unref (stream->rgb8_palette);
9860 stream->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
9861 palette_data, palette_size, 0, palette_size, palette_data, g_free);
9863 s = gst_caps_get_structure (stream->caps, 0);
9865 /* non-raw video has a palette_data property. raw video has the palette as
9866 * an extra plane that we append to the output buffers before we push
9868 if (!gst_structure_has_name (s, "video/x-raw")) {
9871 palette = gst_buffer_new ();
9872 gst_buffer_append_memory (palette, stream->rgb8_palette);
9873 stream->rgb8_palette = NULL;
9875 gst_caps_set_simple (stream->caps, "palette_data",
9876 GST_TYPE_BUFFER, palette, NULL);
9877 gst_buffer_unref (palette);
9879 } else if (palette_count != 0) {
9880 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
9881 (NULL), ("Unsupported palette depth %d", depth));
9884 GST_LOG_OBJECT (qtdemux, "frame count: %u",
9885 QT_UINT16 (stsd_data + offset + 48));
9891 /* pick 'the' stsd child */
9892 mp4v = qtdemux_tree_get_child_by_index (stsd, 0);
9893 if (!stream->protected) {
9894 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
9898 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) {
9904 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
9905 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
9906 colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
9907 fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
9911 const guint8 *pasp_data = (const guint8 *) pasp->data;
9912 gint len = QT_UINT32 (pasp_data);
9915 stream->par_w = QT_UINT32 (pasp_data + 8);
9916 stream->par_h = QT_UINT32 (pasp_data + 12);
9927 const guint8 *fiel_data = (const guint8 *) fiel->data;
9928 gint len = QT_UINT32 (fiel_data);
9931 stream->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
9932 stream->field_order = GST_READ_UINT8 (fiel_data + 9);
9937 const guint8 *colr_data = (const guint8 *) colr->data;
9938 gint len = QT_UINT32 (colr_data);
9940 if (len == 19 || len == 18) {
9941 guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
9943 if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
9944 guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
9945 guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
9946 guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
9947 gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
9949 switch (primaries) {
9951 stream->colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT709;
9954 stream->colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT470BG;
9957 stream->colorimetry.primaries =
9958 GST_VIDEO_COLOR_PRIMARIES_SMPTE170M;
9961 stream->colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT2020;
9967 switch (transfer_function) {
9969 stream->colorimetry.transfer = GST_VIDEO_TRANSFER_BT709;
9972 stream->colorimetry.transfer = GST_VIDEO_TRANSFER_SMPTE240M;
9980 stream->colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT709;
9983 stream->colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT601;
9986 stream->colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_SMPTE240M;
9989 stream->colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT2020;
9995 stream->colorimetry.range =
9996 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
9997 GST_VIDEO_COLOR_RANGE_16_235;
9999 GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
10002 GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
10007 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->stream_tags);
10014 gint len = QT_UINT32 (stsd_data) - 0x66;
10015 const guint8 *avc_data = stsd_data + 0x66;
10018 while (len >= 0x8) {
10021 if (QT_UINT32 (avc_data) <= len)
10022 size = QT_UINT32 (avc_data) - 0x8;
10027 /* No real data, so break out */
10030 switch (QT_FOURCC (avc_data + 0x4)) {
10033 /* parse, if found */
10036 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
10038 /* First 4 bytes are the length of the atom, the next 4 bytes
10039 * are the fourcc, the next 1 byte is the version, and the
10040 * subsequent bytes are profile_tier_level structure like data. */
10041 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
10042 avc_data + 8 + 1, size - 1);
10043 buf = gst_buffer_new_and_alloc (size);
10044 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
10045 gst_caps_set_simple (stream->caps,
10046 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10047 gst_buffer_unref (buf);
10055 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
10057 /* First 4 bytes are the length of the atom, the next 4 bytes
10058 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
10059 * next 1 byte is the version, and the
10060 * subsequent bytes are sequence parameter set like data. */
10062 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
10064 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
10065 avc_data + 8 + 40 + 1, size - 1);
10067 buf = gst_buffer_new_and_alloc (size);
10068 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
10069 gst_caps_set_simple (stream->caps,
10070 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10071 gst_buffer_unref (buf);
10077 guint avg_bitrate, max_bitrate;
10079 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
10083 max_bitrate = QT_UINT32 (avc_data + 0xc);
10084 avg_bitrate = QT_UINT32 (avc_data + 0x10);
10086 if (!max_bitrate && !avg_bitrate)
10089 /* Some muxers seem to swap the average and maximum bitrates
10090 * (I'm looking at you, YouTube), so we swap for sanity. */
10091 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
10092 guint temp = avg_bitrate;
10094 avg_bitrate = max_bitrate;
10095 max_bitrate = temp;
10098 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
10099 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
10100 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
10102 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
10103 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
10104 GST_TAG_BITRATE, avg_bitrate, NULL);
10115 avc_data += size + 8;
10124 gint len = QT_UINT32 (stsd_data) - 0x66;
10125 const guint8 *hevc_data = stsd_data + 0x66;
10128 while (len >= 0x8) {
10131 if (QT_UINT32 (hevc_data) <= len)
10132 size = QT_UINT32 (hevc_data) - 0x8;
10137 /* No real data, so break out */
10140 switch (QT_FOURCC (hevc_data + 0x4)) {
10143 /* parse, if found */
10146 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
10148 /* First 4 bytes are the length of the atom, the next 4 bytes
10149 * are the fourcc, the next 1 byte is the version, and the
10150 * subsequent bytes are sequence parameter set like data. */
10151 gst_codec_utils_h265_caps_set_level_tier_and_profile
10152 (stream->caps, hevc_data + 8 + 1, size - 1);
10154 buf = gst_buffer_new_and_alloc (size);
10155 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
10156 gst_caps_set_simple (stream->caps,
10157 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10158 gst_buffer_unref (buf);
10165 hevc_data += size + 8;
10178 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
10179 GST_FOURCC_ARGS (fourcc));
10181 /* codec data might be in glbl extension atom */
10183 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
10189 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
10191 len = QT_UINT32 (data);
10194 buf = gst_buffer_new_and_alloc (len);
10195 gst_buffer_fill (buf, 0, data + 8, len);
10196 gst_caps_set_simple (stream->caps,
10197 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10198 gst_buffer_unref (buf);
10205 /* see annex I of the jpeg2000 spec */
10206 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
10207 const guint8 *data;
10208 const gchar *colorspace = NULL;
10210 guint32 ncomp_map = 0;
10211 gint32 *comp_map = NULL;
10212 guint32 nchan_def = 0;
10213 gint32 *chan_def = NULL;
10215 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
10216 /* some required atoms */
10217 mjp2 = qtdemux_tree_get_child_by_index (stsd, 0);
10220 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
10224 /* number of components; redundant with info in codestream, but useful
10226 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
10227 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
10229 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
10231 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
10234 GST_DEBUG_OBJECT (qtdemux, "found colr");
10235 /* extract colour space info */
10236 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
10237 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
10239 colorspace = "sRGB";
10242 colorspace = "GRAY";
10245 colorspace = "sYUV";
10253 /* colr is required, and only values 16, 17, and 18 are specified,
10254 so error if we have no colorspace */
10257 /* extract component mapping */
10258 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
10260 guint32 cmap_len = 0;
10262 cmap_len = QT_UINT32 (cmap->data);
10263 if (cmap_len >= 8) {
10264 /* normal box, subtract off header */
10266 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
10267 if (cmap_len % 4 == 0) {
10268 ncomp_map = (cmap_len / 4);
10269 comp_map = g_new0 (gint32, ncomp_map);
10270 for (i = 0; i < ncomp_map; i++) {
10273 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
10274 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
10275 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
10276 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
10281 /* extract channel definitions */
10282 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
10284 guint32 cdef_len = 0;
10286 cdef_len = QT_UINT32 (cdef->data);
10287 if (cdef_len >= 10) {
10288 /* normal box, subtract off header and len */
10290 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
10291 if (cdef_len % 6 == 0) {
10292 nchan_def = (cdef_len / 6);
10293 chan_def = g_new0 (gint32, nchan_def);
10294 for (i = 0; i < nchan_def; i++)
10296 for (i = 0; i < nchan_def; i++) {
10297 guint16 cn, typ, asoc;
10298 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
10299 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
10300 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
10301 if (cn < nchan_def) {
10304 chan_def[cn] = asoc;
10307 chan_def[cn] = 0; /* alpha */
10310 chan_def[cn] = -typ;
10318 gst_caps_set_simple (stream->caps,
10319 "num-components", G_TYPE_INT, ncomp, NULL);
10320 gst_caps_set_simple (stream->caps,
10321 "colorspace", G_TYPE_STRING, colorspace, NULL);
10324 GValue arr = { 0, };
10325 GValue elt = { 0, };
10327 g_value_init (&arr, GST_TYPE_ARRAY);
10328 g_value_init (&elt, G_TYPE_INT);
10329 for (i = 0; i < ncomp_map; i++) {
10330 g_value_set_int (&elt, comp_map[i]);
10331 gst_value_array_append_value (&arr, &elt);
10333 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
10334 "component-map", &arr);
10335 g_value_unset (&elt);
10336 g_value_unset (&arr);
10341 GValue arr = { 0, };
10342 GValue elt = { 0, };
10344 g_value_init (&arr, GST_TYPE_ARRAY);
10345 g_value_init (&elt, G_TYPE_INT);
10346 for (i = 0; i < nchan_def; i++) {
10347 g_value_set_int (&elt, chan_def[i]);
10348 gst_value_array_append_value (&arr, &elt);
10350 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
10351 "channel-definitions", &arr);
10352 g_value_unset (&elt);
10353 g_value_unset (&arr);
10357 /* some optional atoms */
10358 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
10359 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
10361 /* indicate possible fields in caps */
10363 data = (guint8 *) field->data + 8;
10365 gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
10366 (gint) * data, NULL);
10368 /* add codec_data if provided */
10373 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
10374 data = prefix->data;
10375 len = QT_UINT32 (data);
10378 buf = gst_buffer_new_and_alloc (len);
10379 gst_buffer_fill (buf, 0, data + 8, len);
10380 gst_caps_set_simple (stream->caps,
10381 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10382 gst_buffer_unref (buf);
10389 /* https://developer.apple.com/standards/qtff-2001.pdf,
10390 * page 92, "Video Sample Description", under table 3.1 */
10393 const gint compressor_offset = 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
10394 const gint min_size = compressor_offset + 32 + 2 + 2;
10397 guint16 color_table_id = 0;
10400 GST_DEBUG_OBJECT (qtdemux, "found jpeg");
10402 /* recover information on interlaced/progressive */
10403 jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
10407 len = QT_UINT32 (jpeg->data);
10408 GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
10410 if (len >= min_size) {
10411 gst_byte_reader_init (&br, jpeg->data, len);
10413 gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
10414 gst_byte_reader_get_uint16_le (&br, &color_table_id);
10415 if (color_table_id != 0) {
10416 /* the spec says there can be concatenated chunks in the data, and we want
10417 * to find one called field. Walk through them. */
10418 gint offset = min_size;
10419 while (offset + 8 < len) {
10420 guint32 size = 0, tag;
10421 ok = gst_byte_reader_get_uint32_le (&br, &size);
10422 ok &= gst_byte_reader_get_uint32_le (&br, &tag);
10423 if (!ok || size < 8) {
10424 GST_WARNING_OBJECT (qtdemux,
10425 "Failed to walk optional chunk list");
10428 GST_DEBUG_OBJECT (qtdemux,
10429 "Found optional %4.4s chunk, size %u", (const char *) &tag,
10431 if (tag == FOURCC_fiel) {
10432 guint8 n_fields, ordering;
10433 gst_byte_reader_get_uint8 (&br, &n_fields);
10434 gst_byte_reader_get_uint8 (&br, &ordering);
10435 if (n_fields == 1 || n_fields == 2) {
10436 GST_DEBUG_OBJECT (qtdemux,
10437 "Found fiel tag with %u fields, ordering %u", n_fields,
10440 gst_caps_set_simple (stream->caps, "interlace-mode",
10441 G_TYPE_STRING, "interleaved", NULL);
10443 GST_WARNING_OBJECT (qtdemux,
10444 "Found fiel tag with invalid fields (%u)", n_fields);
10450 GST_DEBUG_OBJECT (qtdemux,
10451 "Color table ID is 0, not trying to get interlacedness");
10454 GST_WARNING_OBJECT (qtdemux,
10455 "Length of jpeg chunk is too small, not trying to get interlacedness");
10464 GstBuffer *seqh = NULL;
10465 guint8 *gamma_data = NULL;
10466 gint len = QT_UINT32 (stsd_data);
10468 qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
10470 gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
10471 QT_FP32 (gamma_data), NULL);
10474 /* sorry for the bad name, but we don't know what this is, other
10475 * than its own fourcc */
10476 gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
10478 gst_buffer_unref (seqh);
10481 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
10482 buf = gst_buffer_new_and_alloc (len);
10483 gst_buffer_fill (buf, 0, stsd_data, len);
10484 gst_caps_set_simple (stream->caps,
10485 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10486 gst_buffer_unref (buf);
10492 gst_caps_set_simple (stream->caps,
10493 "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
10498 GNode *xith, *xdxt;
10500 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
10501 xith = qtdemux_tree_get_child_by_index (stsd, 0);
10505 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
10509 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
10510 /* collect the headers and store them in a stream list so that we can
10511 * send them out first */
10512 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
10522 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
10523 ovc1 = qtdemux_tree_get_child_by_index (stsd, 0);
10526 ovc1_data = ovc1->data;
10527 ovc1_len = QT_UINT32 (ovc1_data);
10528 if (ovc1_len <= 198) {
10529 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
10532 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
10533 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
10534 gst_caps_set_simple (stream->caps,
10535 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10536 gst_buffer_unref (buf);
10541 gint len = QT_UINT32 (stsd_data) - 0x66;
10542 const guint8 *vc1_data = stsd_data + 0x66;
10548 if (QT_UINT32 (vc1_data) <= len)
10549 size = QT_UINT32 (vc1_data) - 8;
10554 /* No real data, so break out */
10557 switch (QT_FOURCC (vc1_data + 0x4)) {
10558 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
10562 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
10563 buf = gst_buffer_new_and_alloc (size);
10564 gst_buffer_fill (buf, 0, vc1_data + 8, size);
10565 gst_caps_set_simple (stream->caps,
10566 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10567 gst_buffer_unref (buf);
10574 vc1_data += size + 8;
10583 GST_INFO_OBJECT (qtdemux,
10584 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10585 GST_FOURCC_ARGS (fourcc), stream->caps);
10587 } else if (stream->subtype == FOURCC_soun) {
10588 int version, samplesize;
10589 guint16 compression_id;
10590 gboolean amrwb = FALSE;
10593 /* sample description entry (16) + sound sample description v0 (20) */
10597 version = QT_UINT32 (stsd_data + offset);
10598 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
10599 samplesize = QT_UINT16 (stsd_data + offset + 10);
10600 compression_id = QT_UINT16 (stsd_data + offset + 12);
10601 stream->rate = QT_FP32 (stsd_data + offset + 16);
10603 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
10604 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
10605 QT_UINT32 (stsd_data + offset + 4));
10606 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
10607 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
10608 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
10609 GST_LOG_OBJECT (qtdemux, "packet size: %d",
10610 QT_UINT16 (stsd_data + offset + 14));
10611 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
10613 if (compression_id == 0xfffe)
10614 stream->sampled = TRUE;
10616 /* first assume uncompressed audio */
10617 stream->bytes_per_sample = samplesize / 8;
10618 stream->samples_per_frame = stream->n_channels;
10619 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
10620 stream->samples_per_packet = stream->samples_per_frame;
10621 stream->bytes_per_packet = stream->bytes_per_sample;
10625 /* Yes, these have to be hard-coded */
10628 stream->samples_per_packet = 6;
10629 stream->bytes_per_packet = 1;
10630 stream->bytes_per_frame = 1 * stream->n_channels;
10631 stream->bytes_per_sample = 1;
10632 stream->samples_per_frame = 6 * stream->n_channels;
10637 stream->samples_per_packet = 3;
10638 stream->bytes_per_packet = 1;
10639 stream->bytes_per_frame = 1 * stream->n_channels;
10640 stream->bytes_per_sample = 1;
10641 stream->samples_per_frame = 3 * stream->n_channels;
10646 stream->samples_per_packet = 64;
10647 stream->bytes_per_packet = 34;
10648 stream->bytes_per_frame = 34 * stream->n_channels;
10649 stream->bytes_per_sample = 2;
10650 stream->samples_per_frame = 64 * stream->n_channels;
10656 stream->samples_per_packet = 1;
10657 stream->bytes_per_packet = 1;
10658 stream->bytes_per_frame = 1 * stream->n_channels;
10659 stream->bytes_per_sample = 1;
10660 stream->samples_per_frame = 1 * stream->n_channels;
10665 stream->samples_per_packet = 160;
10666 stream->bytes_per_packet = 33;
10667 stream->bytes_per_frame = 33 * stream->n_channels;
10668 stream->bytes_per_sample = 2;
10669 stream->samples_per_frame = 160 * stream->n_channels;
10676 if (version == 0x00010000) {
10677 /* sample description entry (16) + sound sample description v1 (20+16) */
10688 /* only parse extra decoding config for non-pcm audio */
10689 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
10690 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
10691 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
10692 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
10694 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
10695 stream->samples_per_packet);
10696 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
10697 stream->bytes_per_packet);
10698 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
10699 stream->bytes_per_frame);
10700 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
10701 stream->bytes_per_sample);
10703 if (!stream->sampled && stream->bytes_per_packet) {
10704 stream->samples_per_frame = (stream->bytes_per_frame /
10705 stream->bytes_per_packet) * stream->samples_per_packet;
10706 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
10707 stream->samples_per_frame);
10712 } else if (version == 0x00020000) {
10719 /* sample description entry (16) + sound sample description v2 (56) */
10723 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
10724 stream->rate = qtfp.fp;
10725 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
10727 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
10728 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
10729 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
10730 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
10731 QT_UINT32 (stsd_data + offset + 20));
10732 GST_LOG_OBJECT (qtdemux, "format flags: %X",
10733 QT_UINT32 (stsd_data + offset + 24));
10734 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
10735 QT_UINT32 (stsd_data + offset + 28));
10736 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
10737 QT_UINT32 (stsd_data + offset + 32));
10738 } else if (version != 0x00000) {
10739 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x", version);
10743 gst_caps_unref (stream->caps);
10745 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc,
10746 stsd_data + 32, len - 16, &codec);
10754 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
10756 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
10758 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
10760 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
10763 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
10764 gst_caps_set_simple (stream->caps,
10765 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE", NULL);
10771 const guint8 *owma_data;
10772 const gchar *codec_name = NULL;
10776 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
10777 /* FIXME this should also be gst_riff_strf_auds,
10778 * but the latter one is actually missing bits-per-sample :( */
10783 gint32 nSamplesPerSec;
10784 gint32 nAvgBytesPerSec;
10785 gint16 nBlockAlign;
10786 gint16 wBitsPerSample;
10789 WAVEFORMATEX *wfex;
10791 GST_DEBUG_OBJECT (qtdemux, "parse owma");
10792 owma_data = stsd_entry_data;
10793 owma_len = QT_UINT32 (owma_data);
10794 if (owma_len <= 54) {
10795 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
10798 wfex = (WAVEFORMATEX *) (owma_data + 36);
10799 buf = gst_buffer_new_and_alloc (owma_len - 54);
10800 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
10801 if (wfex->wFormatTag == 0x0161) {
10802 codec_name = "Windows Media Audio";
10804 } else if (wfex->wFormatTag == 0x0162) {
10805 codec_name = "Windows Media Audio 9 Pro";
10807 } else if (wfex->wFormatTag == 0x0163) {
10808 codec_name = "Windows Media Audio 9 Lossless";
10809 /* is that correct? gstffmpegcodecmap.c is missing it, but
10810 * fluendo codec seems to support it */
10814 gst_caps_set_simple (stream->caps,
10815 "codec_data", GST_TYPE_BUFFER, buf,
10816 "wmaversion", G_TYPE_INT, version,
10817 "block_align", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->nBlockAlign),
10818 "bitrate", G_TYPE_INT, GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec),
10819 "width", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
10820 "depth", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
10822 gst_buffer_unref (buf);
10826 codec = g_strdup (codec_name);
10832 gint len = QT_UINT32 (stsd_data) - offset;
10833 const guint8 *wfex_data = stsd_data + offset;
10834 const gchar *codec_name = NULL;
10836 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
10837 /* FIXME this should also be gst_riff_strf_auds,
10838 * but the latter one is actually missing bits-per-sample :( */
10843 gint32 nSamplesPerSec;
10844 gint32 nAvgBytesPerSec;
10845 gint16 nBlockAlign;
10846 gint16 wBitsPerSample;
10851 /* FIXME: unify with similar wavformatex parsing code above */
10852 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
10858 if (QT_UINT32 (wfex_data) <= len)
10859 size = QT_UINT32 (wfex_data) - 8;
10864 /* No real data, so break out */
10867 switch (QT_FOURCC (wfex_data + 4)) {
10868 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
10870 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
10875 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
10876 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
10877 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
10878 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
10879 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
10880 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
10881 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
10883 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
10884 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
10885 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
10886 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
10887 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
10888 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
10890 if (wfex.wFormatTag == 0x0161) {
10891 codec_name = "Windows Media Audio";
10893 } else if (wfex.wFormatTag == 0x0162) {
10894 codec_name = "Windows Media Audio 9 Pro";
10896 } else if (wfex.wFormatTag == 0x0163) {
10897 codec_name = "Windows Media Audio 9 Lossless";
10898 /* is that correct? gstffmpegcodecmap.c is missing it, but
10899 * fluendo codec seems to support it */
10903 gst_caps_set_simple (stream->caps,
10904 "wmaversion", G_TYPE_INT, version,
10905 "block_align", G_TYPE_INT, wfex.nBlockAlign,
10906 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
10907 "width", G_TYPE_INT, wfex.wBitsPerSample,
10908 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
10910 if (size > wfex.cbSize) {
10913 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
10914 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
10915 size - wfex.cbSize);
10916 gst_caps_set_simple (stream->caps,
10917 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10918 gst_buffer_unref (buf);
10920 GST_WARNING_OBJECT (qtdemux, "no codec data");
10925 codec = g_strdup (codec_name);
10933 wfex_data += size + 8;
10939 const guint8 *opus_data;
10940 guint8 *channel_mapping = NULL;
10943 guint8 channel_mapping_family;
10944 guint8 stream_count;
10945 guint8 coupled_count;
10948 opus_data = stsd_entry_data;
10950 channels = GST_READ_UINT8 (opus_data + 45);
10951 rate = GST_READ_UINT32_LE (opus_data + 48);
10952 channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
10953 stream_count = GST_READ_UINT8 (opus_data + 55);
10954 coupled_count = GST_READ_UINT8 (opus_data + 56);
10956 if (channels > 0) {
10957 channel_mapping = g_malloc (channels * sizeof (guint8));
10958 for (i = 0; i < channels; i++)
10959 channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
10962 stream->caps = gst_codec_utils_opus_create_caps (rate, channels,
10963 channel_mapping_family, stream_count, coupled_count,
10975 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
10976 GST_TAG_AUDIO_CODEC, codec, NULL);
10980 /* some bitrate info may have ended up in caps */
10981 s = gst_caps_get_structure (stream->caps, 0);
10982 gst_structure_get_int (s, "bitrate", &bitrate);
10984 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
10985 GST_TAG_BITRATE, bitrate, NULL);
10988 mp4a = qtdemux_tree_get_child_by_index (stsd, 0);
10989 if (!stream->protected) {
10991 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) {
10995 if (stream->protected && fourcc == FOURCC_mp4a) {
10996 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) {
11000 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_mp4a) {
11008 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
11010 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
11012 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
11016 /* If the fourcc's bottom 16 bits gives 'sm', then the top
11017 16 bits is a byte-swapped wave-style codec identifier,
11018 and we can find a WAVE header internally to a 'wave' atom here.
11019 This can more clearly be thought of as 'ms' as the top 16 bits, and a
11020 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
11023 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
11024 if (len < offset + 20) {
11025 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
11027 guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
11028 const guint8 *data = stsd_data + offset + 16;
11030 GNode *waveheadernode;
11032 wavenode = g_node_new ((guint8 *) data);
11033 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
11034 const guint8 *waveheader;
11037 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
11038 if (waveheadernode) {
11039 waveheader = (const guint8 *) waveheadernode->data;
11040 headerlen = QT_UINT32 (waveheader);
11042 if (headerlen > 8) {
11043 gst_riff_strf_auds *header = NULL;
11044 GstBuffer *headerbuf;
11050 headerbuf = gst_buffer_new_and_alloc (headerlen);
11051 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
11053 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
11054 headerbuf, &header, &extra)) {
11055 gst_caps_unref (stream->caps);
11056 /* FIXME: Need to do something with the channel reorder map */
11057 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
11058 header, extra, NULL, NULL, NULL);
11061 gst_buffer_unref (extra);
11066 GST_DEBUG ("Didn't find waveheadernode for this codec");
11068 g_node_destroy (wavenode);
11071 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->stream_tags);
11075 /* FIXME: what is in the chunk? */
11078 gint len = QT_UINT32 (stsd_data);
11080 /* seems to be always = 116 = 0x74 */
11086 gint len = QT_UINT32 (stsd_data);
11089 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
11091 gst_buffer_fill (buf, 0, stsd_data + 0x4C, len - 0x4C);
11092 gst_caps_set_simple (stream->caps,
11093 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11094 gst_buffer_unref (buf);
11096 gst_caps_set_simple (stream->caps,
11097 "samplesize", G_TYPE_INT, samplesize, NULL);
11102 GNode *alac, *wave = NULL;
11104 /* apparently, m4a has this atom appended directly in the stsd entry,
11105 * while mov has it in a wave atom */
11106 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
11108 /* alac now refers to stsd entry atom */
11109 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
11111 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
11113 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
11116 const guint8 *alac_data = alac->data;
11117 gint len = QT_UINT32 (alac->data);
11121 GST_DEBUG_OBJECT (qtdemux,
11122 "discarding alac atom with unexpected len %d", len);
11124 /* codec-data contains alac atom size and prefix,
11125 * ffmpeg likes it that way, not quite gst-ish though ...*/
11126 buf = gst_buffer_new_and_alloc (len);
11127 gst_buffer_fill (buf, 0, alac->data, len);
11128 gst_caps_set_simple (stream->caps,
11129 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11130 gst_buffer_unref (buf);
11132 stream->bytes_per_frame = QT_UINT32 (alac_data + 12);
11133 stream->n_channels = QT_UINT8 (alac_data + 21);
11134 stream->rate = QT_UINT32 (alac_data + 32);
11137 gst_caps_set_simple (stream->caps,
11138 "samplesize", G_TYPE_INT, samplesize, NULL);
11143 /* The codingname of the sample entry is 'fLaC' */
11144 GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
11147 /* The 'dfLa' box is added to the sample entry to convey
11148 initializing information for the decoder. */
11149 const GNode *dfla =
11150 qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
11153 const guint32 len = QT_UINT32 (dfla->data);
11155 /* Must contain at least dfLa box header (12),
11156 * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
11158 GST_DEBUG_OBJECT (qtdemux,
11159 "discarding dfla atom with unexpected len %d", len);
11161 /* skip dfLa header to get the METADATA_BLOCKs */
11162 const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
11163 const guint32 metadata_blocks_len = len - 12;
11165 gchar *stream_marker = g_strdup ("fLaC");
11166 GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
11167 strlen (stream_marker));
11170 guint32 remainder = 0;
11171 guint32 block_size = 0;
11172 gboolean is_last = FALSE;
11174 GValue array = G_VALUE_INIT;
11175 GValue value = G_VALUE_INIT;
11177 g_value_init (&array, GST_TYPE_ARRAY);
11178 g_value_init (&value, GST_TYPE_BUFFER);
11180 gst_value_set_buffer (&value, block);
11181 gst_value_array_append_value (&array, &value);
11182 g_value_reset (&value);
11184 gst_buffer_unref (block);
11186 /* check there's at least one METADATA_BLOCK_HEADER's worth
11187 * of data, and we haven't already finished parsing */
11188 while (!is_last && ((index + 3) < metadata_blocks_len)) {
11189 remainder = metadata_blocks_len - index;
11191 /* add the METADATA_BLOCK_HEADER size to the signalled size */
11193 (metadata_blocks[index + 1] << 16) +
11194 (metadata_blocks[index + 2] << 8) +
11195 metadata_blocks[index + 3];
11197 /* be careful not to read off end of box */
11198 if (block_size > remainder) {
11202 is_last = metadata_blocks[index] >> 7;
11204 block = gst_buffer_new_and_alloc (block_size);
11206 gst_buffer_fill (block, 0, &metadata_blocks[index],
11209 gst_value_set_buffer (&value, block);
11210 gst_value_array_append_value (&array, &value);
11211 g_value_reset (&value);
11213 gst_buffer_unref (block);
11215 index += block_size;
11218 /* only append the metadata if we successfully read all of it */
11220 gst_structure_set_value (gst_caps_get_structure (stream->caps,
11221 0), "streamheader", &array);
11223 GST_WARNING_OBJECT (qtdemux,
11224 "discarding all METADATA_BLOCKs due to invalid "
11225 "block_size %d at idx %d, rem %d", block_size, index,
11229 g_value_unset (&value);
11230 g_value_unset (&array);
11232 /* The sample rate obtained from the stsd may not be accurate
11233 * since it cannot represent rates greater than 65535Hz, so
11234 * override that value with the sample rate from the
11235 * METADATA_BLOCK_STREAMINFO block */
11237 (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
11248 gint len = QT_UINT32 (stsd_data);
11251 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
11254 gst_buffer_fill (buf, 0, stsd_data + 0x34, len - 0x34);
11256 /* If we have enough data, let's try to get the 'damr' atom. See
11257 * the 3GPP container spec (26.244) for more details. */
11258 if ((len - 0x34) > 8 &&
11259 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
11260 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11261 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
11264 gst_caps_set_simple (stream->caps,
11265 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11266 gst_buffer_unref (buf);
11272 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
11273 gint len = QT_UINT32 (stsd_data);
11276 guint16 sound_version = QT_UINT16 (stsd_data + 32);
11278 if (sound_version == 1) {
11279 guint16 channels = QT_UINT16 (stsd_data + 40);
11280 guint32 time_scale = QT_UINT32 (stsd_data + 46);
11281 guint8 codec_data[2];
11283 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
11285 gint sample_rate_index =
11286 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
11288 /* build AAC codec data */
11289 codec_data[0] = profile << 3;
11290 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
11291 codec_data[1] = (sample_rate_index & 0x01) << 7;
11292 codec_data[1] |= (channels & 0xF) << 3;
11294 buf = gst_buffer_new_and_alloc (2);
11295 gst_buffer_fill (buf, 0, codec_data, 2);
11296 gst_caps_set_simple (stream->caps,
11297 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11298 gst_buffer_unref (buf);
11304 GST_INFO_OBJECT (qtdemux,
11305 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11309 GST_INFO_OBJECT (qtdemux,
11310 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11311 GST_FOURCC_ARGS (fourcc), stream->caps);
11313 } else if (stream->subtype == FOURCC_strm) {
11314 if (fourcc == FOURCC_rtsp) {
11315 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
11317 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
11318 GST_FOURCC_ARGS (fourcc));
11319 goto unknown_stream;
11321 stream->sampled = TRUE;
11322 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
11323 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
11325 stream->sampled = TRUE;
11326 stream->sparse = TRUE;
11329 qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
11331 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11332 GST_TAG_SUBTITLE_CODEC, codec, NULL);
11337 /* hunt for sort-of codec data */
11341 GNode *mp4s = NULL;
11342 GNode *esds = NULL;
11344 /* look for palette in a stsd->mp4s->esds sub-atom */
11345 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
11347 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
11348 if (esds == NULL) {
11350 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
11354 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->stream_tags);
11358 GST_INFO_OBJECT (qtdemux,
11359 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11362 GST_INFO_OBJECT (qtdemux,
11363 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11364 GST_FOURCC_ARGS (fourcc), stream->caps);
11366 /* everything in 1 sample */
11367 stream->sampled = TRUE;
11370 qtdemux_generic_caps (qtdemux, stream, fourcc, stsd_data, &codec);
11372 if (stream->caps == NULL)
11373 goto unknown_stream;
11376 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11377 GST_TAG_SUBTITLE_CODEC, codec, NULL);
11383 /* promote to sampled format */
11384 if (stream->fourcc == FOURCC_samr) {
11385 /* force mono 8000 Hz for AMR */
11386 stream->sampled = TRUE;
11387 stream->n_channels = 1;
11388 stream->rate = 8000;
11389 } else if (stream->fourcc == FOURCC_sawb) {
11390 /* force mono 16000 Hz for AMR-WB */
11391 stream->sampled = TRUE;
11392 stream->n_channels = 1;
11393 stream->rate = 16000;
11394 } else if (stream->fourcc == FOURCC_mp4a) {
11395 stream->sampled = TRUE;
11398 /* collect sample information */
11399 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
11400 goto samples_failed;
11402 if (qtdemux->fragmented) {
11405 /* need all moov samples as basis; probably not many if any at all */
11406 /* prevent moof parsing taking of at this time */
11407 offset = qtdemux->moof_offset;
11408 qtdemux->moof_offset = 0;
11409 if (stream->n_samples &&
11410 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
11411 qtdemux->moof_offset = offset;
11412 goto samples_failed;
11414 qtdemux->moof_offset = 0;
11415 /* movie duration more reliable in this case (e.g. mehd) */
11416 if (qtdemux->segment.duration &&
11417 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
11419 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
11422 /* configure segments */
11423 if (!qtdemux_parse_segments (qtdemux, stream, trak))
11424 goto segments_failed;
11426 /* add some language tag, if useful */
11427 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
11428 strcmp (stream->lang_id, "und")) {
11429 const gchar *lang_code;
11431 /* convert ISO 639-2 code to ISO 639-1 */
11432 lang_code = gst_tag_get_language_code (stream->lang_id);
11433 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11434 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
11437 /* Check for UDTA tags */
11438 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
11439 qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
11442 /* now we are ready to add the stream */
11443 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
11444 goto too_many_streams;
11446 if (!qtdemux->got_moov) {
11447 qtdemux->streams[qtdemux->n_streams] = stream;
11448 qtdemux->n_streams++;
11449 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
11457 GST_INFO_OBJECT (qtdemux, "skip disabled track");
11459 gst_qtdemux_stream_free (qtdemux, stream);
11464 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
11465 (_("This file is corrupt and cannot be played.")), (NULL));
11467 gst_qtdemux_stream_free (qtdemux, stream);
11472 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
11474 gst_qtdemux_stream_free (qtdemux, stream);
11480 /* we posted an error already */
11481 /* free stbl sub-atoms */
11482 gst_qtdemux_stbl_free (stream);
11484 gst_qtdemux_stream_free (qtdemux, stream);
11489 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
11492 gst_qtdemux_stream_free (qtdemux, stream);
11497 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
11498 GST_FOURCC_ARGS (stream->subtype));
11500 gst_qtdemux_stream_free (qtdemux, stream);
11505 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
11506 (_("This file contains too many streams. Only playing first %d"),
11507 GST_QTDEMUX_MAX_STREAMS), (NULL));
11512 /* If we can estimate the overall bitrate, and don't have information about the
11513 * stream bitrate for exactly one stream, this guesses the stream bitrate as
11514 * the overall bitrate minus the sum of the bitrates of all other streams. This
11515 * should be useful for the common case where we have one audio and one video
11516 * stream and can estimate the bitrate of one, but not the other. */
11518 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
11520 QtDemuxStream *stream = NULL;
11521 gint64 size, sys_bitrate, sum_bitrate = 0;
11522 GstClockTime duration;
11526 if (qtdemux->fragmented)
11529 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
11531 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
11533 GST_DEBUG_OBJECT (qtdemux,
11534 "Size in bytes of the stream not known - bailing");
11538 /* Subtract the header size */
11539 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
11540 size, qtdemux->header_size);
11542 if (size < qtdemux->header_size)
11545 size = size - qtdemux->header_size;
11547 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
11548 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
11552 for (i = 0; i < qtdemux->n_streams; i++) {
11553 switch (qtdemux->streams[i]->subtype) {
11556 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
11557 qtdemux->streams[i]->caps);
11558 /* retrieve bitrate, prefer avg then max */
11560 if (qtdemux->streams[i]->stream_tags) {
11561 gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags,
11562 GST_TAG_MAXIMUM_BITRATE, &bitrate);
11563 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
11564 gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags,
11565 GST_TAG_NOMINAL_BITRATE, &bitrate);
11566 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
11567 gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags,
11568 GST_TAG_BITRATE, &bitrate);
11569 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
11572 sum_bitrate += bitrate;
11575 GST_DEBUG_OBJECT (qtdemux,
11576 ">1 stream with unknown bitrate - bailing");
11579 stream = qtdemux->streams[i];
11583 /* For other subtypes, we assume no significant impact on bitrate */
11589 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
11593 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
11595 if (sys_bitrate < sum_bitrate) {
11596 /* This can happen, since sum_bitrate might be derived from maximum
11597 * bitrates and not average bitrates */
11598 GST_DEBUG_OBJECT (qtdemux,
11599 "System bitrate less than sum bitrate - bailing");
11603 bitrate = sys_bitrate - sum_bitrate;
11604 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
11605 ", Stream bitrate = %u", sys_bitrate, bitrate);
11607 if (!stream->stream_tags)
11608 stream->stream_tags = gst_tag_list_new_empty ();
11610 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
11612 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11613 GST_TAG_BITRATE, bitrate, NULL);
11616 static GstFlowReturn
11617 qtdemux_prepare_streams (GstQTDemux * qtdemux)
11620 GstFlowReturn ret = GST_FLOW_OK;
11622 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
11624 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
11625 QtDemuxStream *stream = qtdemux->streams[i];
11626 guint32 sample_num = 0;
11628 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
11629 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
11631 if (qtdemux->fragmented) {
11632 /* need all moov samples first */
11633 GST_OBJECT_LOCK (qtdemux);
11634 while (stream->n_samples == 0)
11635 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
11637 GST_OBJECT_UNLOCK (qtdemux);
11639 /* discard any stray moof */
11640 qtdemux->moof_offset = 0;
11643 /* prepare braking */
11644 if (ret != GST_FLOW_ERROR)
11647 /* in pull mode, we should have parsed some sample info by now;
11648 * and quite some code will not handle no samples.
11649 * in push mode, we'll just have to deal with it */
11650 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
11651 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
11652 gst_qtdemux_remove_stream (qtdemux, i);
11657 /* parse the initial sample for use in setting the frame rate cap */
11658 while (sample_num == 0 && sample_num < stream->n_samples) {
11659 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
11663 if (stream->n_samples > 0 && stream->stbl_index >= 0) {
11664 stream->first_duration = stream->samples[0].duration;
11665 GST_LOG_OBJECT (qtdemux, "stream %d first duration %u",
11666 stream->track_id, stream->first_duration);
11673 static GstFlowReturn
11674 qtdemux_expose_streams (GstQTDemux * qtdemux)
11677 GSList *oldpads = NULL;
11680 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
11682 for (i = 0; i < qtdemux->n_streams; i++) {
11683 QtDemuxStream *stream = qtdemux->streams[i];
11684 GstPad *oldpad = stream->pad;
11687 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
11688 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
11690 if ((stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl) &&
11691 stream->track_id == qtdemux->chapters_track_id) {
11692 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
11693 so that it doesn't look like a subtitle track */
11694 gst_qtdemux_remove_stream (qtdemux, i);
11699 /* now we have all info and can expose */
11700 list = stream->stream_tags;
11701 stream->stream_tags = NULL;
11703 oldpads = g_slist_prepend (oldpads, oldpad);
11704 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
11705 return GST_FLOW_ERROR;
11708 gst_qtdemux_guess_bitrate (qtdemux);
11710 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
11712 for (iter = oldpads; iter; iter = g_slist_next (iter)) {
11713 GstPad *oldpad = iter->data;
11716 event = gst_event_new_eos ();
11717 if (qtdemux->segment_seqnum)
11718 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
11720 gst_pad_push_event (oldpad, event);
11721 gst_pad_set_active (oldpad, FALSE);
11722 gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
11723 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, oldpad);
11724 gst_object_unref (oldpad);
11727 /* check if we should post a redirect in case there is a single trak
11728 * and it is a redirecting trak */
11729 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
11732 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
11733 "an external content");
11734 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
11735 gst_structure_new ("redirect",
11736 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
11738 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
11739 qtdemux->posted_redirect = TRUE;
11742 for (i = 0; i < qtdemux->n_streams; i++) {
11743 QtDemuxStream *stream = qtdemux->streams[i];
11745 qtdemux_do_allocation (qtdemux, stream);
11748 qtdemux->exposed = TRUE;
11749 return GST_FLOW_OK;
11752 /* check if major or compatible brand is 3GP */
11753 static inline gboolean
11754 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
11757 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
11759 } else if (qtdemux->comp_brands != NULL) {
11763 gboolean res = FALSE;
11765 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
11768 while (size >= 4) {
11769 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
11774 gst_buffer_unmap (qtdemux->comp_brands, &map);
11781 /* check if tag is a spec'ed 3GP tag keyword storing a string */
11782 static inline gboolean
11783 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
11785 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
11786 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
11787 || fourcc == FOURCC_albm;
11791 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
11792 const char *tag, const char *dummy, GNode * node)
11794 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11798 gdouble longitude, latitude, altitude;
11801 len = QT_UINT32 (node->data);
11808 /* TODO: language code skipped */
11810 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
11813 /* do not alarm in trivial case, but bail out otherwise */
11814 if (*(data + offset) != 0) {
11815 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
11819 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
11820 GST_TAG_GEO_LOCATION_NAME, name, NULL);
11821 offset += strlen (name);
11825 if (len < offset + 2 + 4 + 4 + 4)
11828 /* +1 +1 = skip null-terminator and location role byte */
11830 /* table in spec says unsigned, semantics say negative has meaning ... */
11831 longitude = QT_SFP32 (data + offset);
11834 latitude = QT_SFP32 (data + offset);
11837 altitude = QT_SFP32 (data + offset);
11839 /* one invalid means all are invalid */
11840 if (longitude >= -180.0 && longitude <= 180.0 &&
11841 latitude >= -90.0 && latitude <= 90.0) {
11842 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
11843 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
11844 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
11845 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
11848 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
11855 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
11862 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
11863 const char *tag, const char *dummy, GNode * node)
11869 len = QT_UINT32 (node->data);
11873 y = QT_UINT16 ((guint8 *) node->data + 12);
11875 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
11878 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
11880 date = g_date_new_dmy (1, 1, y);
11881 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
11882 g_date_free (date);
11886 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
11887 const char *tag, const char *dummy, GNode * node)
11890 char *tag_str = NULL;
11895 len = QT_UINT32 (node->data);
11900 entity = (guint8 *) node->data + offset;
11901 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
11902 GST_DEBUG_OBJECT (qtdemux,
11903 "classification info: %c%c%c%c invalid classification entity",
11904 entity[0], entity[1], entity[2], entity[3]);
11909 table = QT_UINT16 ((guint8 *) node->data + offset);
11911 /* Language code skipped */
11915 /* Tag format: "XXXX://Y[YYYY]/classification info string"
11916 * XXXX: classification entity, fixed length 4 chars.
11917 * Y[YYYY]: classification table, max 5 chars.
11919 tag_str = g_strdup_printf ("----://%u/%s",
11920 table, (char *) node->data + offset);
11922 /* memcpy To be sure we're preserving byte order */
11923 memcpy (tag_str, entity, 4);
11924 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
11926 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
11935 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
11941 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
11942 const char *tag, const char *dummy, GNode * node)
11944 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11950 gboolean ret = TRUE;
11951 const gchar *charset = NULL;
11953 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11955 len = QT_UINT32 (data->data);
11956 type = QT_UINT32 ((guint8 *) data->data + 8);
11957 if (type == 0x00000001 && len > 16) {
11958 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
11961 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
11962 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
11965 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
11969 len = QT_UINT32 (node->data);
11970 type = QT_UINT32 ((guint8 *) node->data + 4);
11971 if ((type >> 24) == 0xa9 && len > 8 + 4) {
11975 /* Type starts with the (C) symbol, so the next data is a list
11976 * of (string size(16), language code(16), string) */
11978 str_len = QT_UINT16 ((guint8 *) node->data + 8);
11979 lang_code = QT_UINT16 ((guint8 *) node->data + 10);
11981 /* the string + fourcc + size + 2 16bit fields,
11982 * means that there are more tags in this atom */
11983 if (len > str_len + 8 + 4) {
11984 /* TODO how to represent the same tag in different languages? */
11985 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
11986 "text alternatives, reading only first one");
11990 len = MIN (len, str_len + 8 + 4); /* remove trailing strings that we don't use */
11991 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
11993 if (lang_code < 0x800) { /* MAC encoded string */
11996 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
11997 QT_FOURCC ((guint8 *) node->data + 4))) {
11998 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
12000 /* we go for 3GP style encoding if major brands claims so,
12001 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
12002 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
12003 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
12004 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
12006 /* 16-bit Language code is ignored here as well */
12007 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
12014 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
12015 ret = FALSE; /* may have to fallback */
12018 GError *err = NULL;
12020 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
12021 charset, NULL, NULL, &err);
12023 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
12024 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
12026 g_error_free (err);
12029 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
12030 len - offset, env_vars);
12033 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
12034 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
12038 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
12045 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
12046 const char *tag, const char *dummy, GNode * node)
12048 qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
12052 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
12053 const char *tag, const char *dummy, GNode * node)
12055 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12057 char *s, *t, *k = NULL;
12062 /* first try normal string tag if major brand not 3GP */
12063 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
12064 if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
12065 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
12066 * let's try it 3gpp way after minor safety check */
12068 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
12074 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
12078 len = QT_UINT32 (data);
12082 count = QT_UINT8 (data + 14);
12084 for (; count; count--) {
12087 if (offset + 1 > len)
12089 slen = QT_UINT8 (data + offset);
12091 if (offset + slen > len)
12093 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
12096 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
12098 t = g_strjoin (",", k, s, NULL);
12106 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
12113 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
12114 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
12123 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
12129 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
12130 const char *tag1, const char *tag2, GNode * node)
12137 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12139 len = QT_UINT32 (data->data);
12140 type = QT_UINT32 ((guint8 *) data->data + 8);
12141 if (type == 0x00000000 && len >= 22) {
12142 n1 = QT_UINT16 ((guint8 *) data->data + 18);
12143 n2 = QT_UINT16 ((guint8 *) data->data + 20);
12145 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
12146 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
12149 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
12150 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
12157 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
12158 const char *tag1, const char *dummy, GNode * node)
12165 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12167 len = QT_UINT32 (data->data);
12168 type = QT_UINT32 ((guint8 *) data->data + 8);
12169 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
12170 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
12171 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
12172 n1 = QT_UINT16 ((guint8 *) data->data + 16);
12174 /* do not add bpm=0 */
12175 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
12176 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
12184 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
12185 const char *tag1, const char *dummy, GNode * node)
12192 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12194 len = QT_UINT32 (data->data);
12195 type = QT_UINT32 ((guint8 *) data->data + 8);
12196 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
12197 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
12198 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
12199 num = QT_UINT32 ((guint8 *) data->data + 16);
12201 /* do not add num=0 */
12202 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
12203 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
12210 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
12211 const char *tag1, const char *dummy, GNode * node)
12218 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12220 len = QT_UINT32 (data->data);
12221 type = QT_UINT32 ((guint8 *) data->data + 8);
12222 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
12223 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
12224 GstTagImageType image_type;
12226 if (gst_tag_list_get_tag_size (taglist, GST_TAG_IMAGE) == 0)
12227 image_type = GST_TAG_IMAGE_TYPE_FRONT_COVER;
12229 image_type = GST_TAG_IMAGE_TYPE_NONE;
12232 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
12233 len - 16, image_type))) {
12234 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
12235 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
12236 gst_sample_unref (sample);
12243 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
12244 const char *tag, const char *dummy, GNode * node)
12251 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12253 len = QT_UINT32 (data->data);
12254 type = QT_UINT32 ((guint8 *) data->data + 8);
12255 if (type == 0x00000001 && len > 16) {
12256 guint y, m = 1, d = 1;
12259 s = g_strndup ((char *) data->data + 16, len - 16);
12260 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
12261 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
12262 if (ret >= 1 && y > 1500 && y < 3000) {
12265 date = g_date_new_dmy (d, m, y);
12266 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
12267 g_date_free (date);
12269 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
12277 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
12278 const char *tag, const char *dummy, GNode * node)
12282 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12284 /* re-route to normal string tag if major brand says so
12285 * or no data atom and compatible brand suggests so */
12286 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
12287 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
12288 qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
12293 guint len, type, n;
12295 len = QT_UINT32 (data->data);
12296 type = QT_UINT32 ((guint8 *) data->data + 8);
12297 if (type == 0x00000000 && len >= 18) {
12298 n = QT_UINT16 ((guint8 *) data->data + 16);
12300 const gchar *genre;
12302 genre = gst_tag_id3_genre_get (n - 1);
12303 if (genre != NULL) {
12304 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
12305 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
12313 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
12314 const gchar * tag, guint8 * data, guint32 datasize)
12319 /* make a copy to have \0 at the end */
12320 datacopy = g_strndup ((gchar *) data, datasize);
12322 /* convert the str to double */
12323 if (sscanf (datacopy, "%lf", &value) == 1) {
12324 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
12325 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
12327 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
12335 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
12336 const char *tag, const char *tag_bis, GNode * node)
12345 const gchar *meanstr;
12346 const gchar *namestr;
12348 /* checking the whole ---- atom size for consistency */
12349 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
12350 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
12354 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
12356 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
12360 meansize = QT_UINT32 (mean->data);
12361 if (meansize <= 12) {
12362 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
12365 meanstr = ((gchar *) mean->data) + 12;
12368 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
12370 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
12374 namesize = QT_UINT32 (name->data);
12375 if (namesize <= 12) {
12376 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
12379 namestr = ((gchar *) name->data) + 12;
12387 * uint24 - data type
12391 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12393 GST_WARNING_OBJECT (demux, "No data atom in this tag");
12396 datasize = QT_UINT32 (data->data);
12397 if (datasize <= 16) {
12398 GST_WARNING_OBJECT (demux, "Data atom too small");
12401 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
12403 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
12404 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
12405 static const struct
12407 const gchar name[28];
12408 const gchar tag[28];
12411 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
12412 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
12413 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
12414 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
12415 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
12416 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
12417 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
12418 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
12422 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
12423 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
12424 switch (gst_tag_get_type (tags[i].tag)) {
12425 case G_TYPE_DOUBLE:
12426 qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
12427 ((guint8 *) data->data) + 16, datasize - 16);
12429 case G_TYPE_STRING:
12430 qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
12439 if (i == G_N_ELEMENTS (tags))
12449 #ifndef GST_DISABLE_GST_DEBUG
12451 gchar *namestr_dbg;
12452 gchar *meanstr_dbg;
12454 meanstr_dbg = g_strndup (meanstr, meansize);
12455 namestr_dbg = g_strndup (namestr, namesize);
12457 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
12458 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
12460 g_free (namestr_dbg);
12461 g_free (meanstr_dbg);
12468 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
12469 const char *tag_bis, GNode * node)
12474 GstTagList *id32_taglist = NULL;
12476 GST_LOG_OBJECT (demux, "parsing ID32");
12479 len = GST_READ_UINT32_BE (data);
12481 /* need at least full box and language tag */
12485 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
12486 gst_buffer_fill (buf, 0, data + 14, len - 14);
12488 id32_taglist = gst_tag_list_from_id3v2_tag (buf);
12489 if (id32_taglist) {
12490 GST_LOG_OBJECT (demux, "parsing ok");
12491 gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
12492 gst_tag_list_unref (id32_taglist);
12494 GST_LOG_OBJECT (demux, "parsing failed");
12497 gst_buffer_unref (buf);
12500 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
12501 const char *tag, const char *tag_bis, GNode * node);
12504 FOURCC_pcst -> if media is a podcast -> bool
12505 FOURCC_cpil -> if media is part of a compilation -> bool
12506 FOURCC_pgap -> if media is part of a gapless context -> bool
12507 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
12510 static const struct
12513 const gchar *gst_tag;
12514 const gchar *gst_tag_bis;
12515 const GstQTDemuxAddTagFunc func;
12518 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
12519 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
12520 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
12521 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
12522 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
12523 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
12524 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
12525 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
12526 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
12527 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
12528 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
12529 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
12530 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
12531 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12532 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12533 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12534 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
12535 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
12536 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
12537 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
12538 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
12539 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
12540 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
12541 qtdemux_tag_add_num}, {
12542 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
12543 qtdemux_tag_add_num}, {
12544 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
12545 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
12546 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
12547 FOURCC_covr, GST_TAG_IMAGE, NULL, qtdemux_tag_add_covr}, {
12548 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
12549 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
12550 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
12551 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
12552 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
12553 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
12554 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
12555 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
12556 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
12557 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
12558 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
12559 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
12560 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
12561 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
12562 qtdemux_tag_add_classification}, {
12563 FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
12564 FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
12565 FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
12567 /* This is a special case, some tags are stored in this
12568 * 'reverse dns naming', according to:
12569 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
12572 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
12573 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
12574 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
12577 struct _GstQtDemuxTagList
12580 GstTagList *taglist;
12582 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
12585 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
12591 const gchar *style;
12596 GstQTDemux *demux = qtdemuxtaglist->demux;
12597 GstTagList *taglist = qtdemuxtaglist->taglist;
12600 len = QT_UINT32 (data);
12601 buf = gst_buffer_new_and_alloc (len);
12602 gst_buffer_fill (buf, 0, data, len);
12604 /* heuristic to determine style of tag */
12605 if (QT_FOURCC (data + 4) == FOURCC_____ ||
12606 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
12608 else if (demux->major_brand == FOURCC_qt__)
12609 style = "quicktime";
12610 /* fall back to assuming iso/3gp tag style */
12614 /* santize the name for the caps. */
12615 for (i = 0; i < 4; i++) {
12616 guint8 d = data[4 + i];
12617 if (g_ascii_isalnum (d))
12618 ndata[i] = g_ascii_tolower (d);
12623 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
12624 ndata[0], ndata[1], ndata[2], ndata[3]);
12625 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
12627 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
12628 sample = gst_sample_new (buf, NULL, NULL, s);
12629 gst_buffer_unref (buf);
12630 g_free (media_type);
12632 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
12635 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
12636 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
12638 gst_sample_unref (sample);
12642 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
12649 GstQtDemuxTagList demuxtaglist;
12651 demuxtaglist.demux = qtdemux;
12652 demuxtaglist.taglist = taglist;
12654 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
12655 if (meta != NULL) {
12656 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
12657 if (ilst == NULL) {
12658 GST_LOG_OBJECT (qtdemux, "no ilst");
12663 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
12667 while (i < G_N_ELEMENTS (add_funcs)) {
12668 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
12672 len = QT_UINT32 (node->data);
12674 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
12675 GST_FOURCC_ARGS (add_funcs[i].fourcc));
12677 add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
12678 add_funcs[i].gst_tag_bis, node);
12680 g_node_destroy (node);
12686 /* parsed nodes have been removed, pass along remainder as blob */
12687 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
12688 (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
12690 /* parse up XMP_ node if existing */
12691 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
12692 if (xmp_ != NULL) {
12694 GstTagList *xmptaglist;
12696 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
12697 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
12698 xmptaglist = gst_tag_list_from_xmp_buffer (buf);
12699 gst_buffer_unref (buf);
12701 qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
12703 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
12709 GstStructure *structure; /* helper for sort function */
12711 guint min_req_bitrate;
12712 guint min_req_qt_version;
12716 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
12718 GstQtReference *ref_a = (GstQtReference *) a;
12719 GstQtReference *ref_b = (GstQtReference *) b;
12721 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
12722 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
12724 /* known bitrates go before unknown; higher bitrates go first */
12725 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
12728 /* sort the redirects and post a message for the application.
12731 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
12733 GstQtReference *best;
12736 GValue list_val = { 0, };
12739 g_assert (references != NULL);
12741 references = g_list_sort (references, qtdemux_redirects_sort_func);
12743 best = (GstQtReference *) references->data;
12745 g_value_init (&list_val, GST_TYPE_LIST);
12747 for (l = references; l != NULL; l = l->next) {
12748 GstQtReference *ref = (GstQtReference *) l->data;
12749 GValue struct_val = { 0, };
12751 ref->structure = gst_structure_new ("redirect",
12752 "new-location", G_TYPE_STRING, ref->location, NULL);
12754 if (ref->min_req_bitrate > 0) {
12755 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
12756 ref->min_req_bitrate, NULL);
12759 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
12760 g_value_set_boxed (&struct_val, ref->structure);
12761 gst_value_list_append_value (&list_val, &struct_val);
12762 g_value_unset (&struct_val);
12763 /* don't free anything here yet, since we need best->structure below */
12766 g_assert (best != NULL);
12767 s = gst_structure_copy (best->structure);
12769 if (g_list_length (references) > 1) {
12770 gst_structure_set_value (s, "locations", &list_val);
12773 g_value_unset (&list_val);
12775 for (l = references; l != NULL; l = l->next) {
12776 GstQtReference *ref = (GstQtReference *) l->data;
12778 gst_structure_free (ref->structure);
12779 g_free (ref->location);
12782 g_list_free (references);
12784 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
12785 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
12786 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
12787 qtdemux->posted_redirect = TRUE;
12790 /* look for redirect nodes, collect all redirect information and
12794 qtdemux_parse_redirects (GstQTDemux * qtdemux)
12796 GNode *rmra, *rmda, *rdrf;
12798 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
12800 GList *redirects = NULL;
12802 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
12804 GstQtReference ref = { NULL, NULL, 0, 0 };
12805 GNode *rmdr, *rmvc;
12807 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
12808 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
12809 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
12810 ref.min_req_bitrate);
12813 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
12814 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
12815 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
12817 #ifndef GST_DISABLE_GST_DEBUG
12818 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
12820 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
12822 GST_LOG_OBJECT (qtdemux,
12823 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
12824 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
12825 bitmask, check_type);
12826 if (package == FOURCC_qtim && check_type == 0) {
12827 ref.min_req_qt_version = version;
12831 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
12837 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
12838 if (ref_len > 20) {
12839 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
12840 ref_data = (guint8 *) rdrf->data + 20;
12841 if (ref_type == FOURCC_alis) {
12842 guint record_len, record_version, fn_len;
12844 if (ref_len > 70) {
12845 /* MacOSX alias record, google for alias-layout.txt */
12846 record_len = QT_UINT16 (ref_data + 4);
12847 record_version = QT_UINT16 (ref_data + 4 + 2);
12848 fn_len = QT_UINT8 (ref_data + 50);
12849 if (record_len > 50 && record_version == 2 && fn_len > 0) {
12850 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
12853 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
12856 } else if (ref_type == FOURCC_url_) {
12857 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
12859 GST_DEBUG_OBJECT (qtdemux,
12860 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
12861 GST_FOURCC_ARGS (ref_type));
12863 if (ref.location != NULL) {
12864 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
12866 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
12868 GST_WARNING_OBJECT (qtdemux,
12869 "Failed to extract redirect location from rdrf atom");
12872 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
12876 /* look for others */
12877 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
12880 if (redirects != NULL) {
12881 qtdemux_process_redirects (qtdemux, redirects);
12887 static GstTagList *
12888 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
12892 if (tags == NULL) {
12893 tags = gst_tag_list_new_empty ();
12894 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
12897 if (qtdemux->major_brand == FOURCC_mjp2)
12898 fmt = "Motion JPEG 2000";
12899 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
12901 else if (qtdemux->major_brand == FOURCC_qt__)
12903 else if (qtdemux->fragmented)
12906 fmt = "ISO MP4/M4A";
12908 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
12909 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
12911 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
12917 /* we have read the complete moov node now.
12918 * This function parses all of the relevant info, creates the traks and
12919 * prepares all data structures for playback
12922 qtdemux_parse_tree (GstQTDemux * qtdemux)
12928 GstClockTime duration;
12930 guint64 creation_time;
12931 GstDateTime *datetime = NULL;
12934 /* make sure we have a usable taglist */
12935 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
12937 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
12938 if (mvhd == NULL) {
12939 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
12940 return qtdemux_parse_redirects (qtdemux);
12943 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
12944 if (version == 1) {
12945 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
12946 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
12947 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
12948 } else if (version == 0) {
12949 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
12950 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
12951 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
12953 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
12957 /* Moving qt creation time (secs since 1904) to unix time */
12958 if (creation_time != 0) {
12959 /* Try to use epoch first as it should be faster and more commonly found */
12960 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
12963 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
12964 /* some data cleansing sanity */
12965 g_get_current_time (&now);
12966 if (now.tv_sec + 24 * 3600 < creation_time) {
12967 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
12969 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
12972 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
12973 GDateTime *dt, *dt_local;
12975 dt = g_date_time_add_seconds (base_dt, creation_time);
12976 dt_local = g_date_time_to_local (dt);
12977 datetime = gst_date_time_new_from_g_date_time (dt_local);
12979 g_date_time_unref (base_dt);
12980 g_date_time_unref (dt);
12984 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
12985 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
12987 gst_date_time_unref (datetime);
12990 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
12991 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
12993 /* check for fragmented file and get some (default) data */
12994 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
12997 GstByteReader mehd_data;
12999 /* let track parsing or anyone know weird stuff might happen ... */
13000 qtdemux->fragmented = TRUE;
13002 /* compensate for total duration */
13003 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
13005 qtdemux_parse_mehd (qtdemux, &mehd_data);
13008 /* set duration in the segment info */
13009 gst_qtdemux_get_duration (qtdemux, &duration);
13011 qtdemux->segment.duration = duration;
13012 /* also do not exceed duration; stop is set that way post seek anyway,
13013 * and segment activation falls back to duration,
13014 * whereas loop only checks stop, so let's align this here as well */
13015 qtdemux->segment.stop = duration;
13018 /* parse all traks */
13019 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
13021 qtdemux_parse_trak (qtdemux, trak);
13022 /* iterate all siblings */
13023 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
13026 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13029 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
13031 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13033 GST_LOG_OBJECT (qtdemux, "No udta node found.");
13036 /* maybe also some tags in meta box */
13037 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
13039 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
13040 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13042 GST_LOG_OBJECT (qtdemux, "No meta node found.");
13045 /* parse any protection system info */
13046 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
13048 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
13049 qtdemux_parse_pssh (qtdemux, pssh);
13050 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
13053 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
13058 /* taken from ffmpeg */
13060 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
13072 len = (len << 7) | (c & 0x7f);
13080 /* this can change the codec originally present in @list */
13082 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
13083 GNode * esds, GstTagList * list)
13085 int len = QT_UINT32 (esds->data);
13086 guint8 *ptr = esds->data;
13087 guint8 *end = ptr + len;
13089 guint8 *data_ptr = NULL;
13091 guint8 object_type_id = 0;
13092 const char *codec_name = NULL;
13093 GstCaps *caps = NULL;
13095 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
13097 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
13099 while (ptr + 1 < end) {
13100 tag = QT_UINT8 (ptr);
13101 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
13103 len = read_descr_size (ptr, end, &ptr);
13104 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
13106 /* Check the stated amount of data is available for reading */
13107 if (len < 0 || ptr + len > end)
13111 case ES_DESCRIPTOR_TAG:
13112 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
13113 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
13116 case DECODER_CONFIG_DESC_TAG:{
13117 guint max_bitrate, avg_bitrate;
13119 object_type_id = QT_UINT8 (ptr);
13120 max_bitrate = QT_UINT32 (ptr + 5);
13121 avg_bitrate = QT_UINT32 (ptr + 9);
13122 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
13123 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
13124 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
13125 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
13126 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
13127 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
13128 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
13129 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
13131 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
13132 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
13133 avg_bitrate, NULL);
13138 case DECODER_SPECIFIC_INFO_TAG:
13139 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
13140 if (object_type_id == 0xe0 && len == 0x40) {
13146 GST_DEBUG_OBJECT (qtdemux,
13147 "Have VOBSUB palette. Creating palette event");
13148 /* move to decConfigDescr data and read palette */
13150 for (i = 0; i < 16; i++) {
13151 clut[i] = QT_UINT32 (data);
13155 s = gst_structure_new ("application/x-gst-dvd", "event",
13156 G_TYPE_STRING, "dvd-spu-clut-change",
13157 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
13158 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
13159 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
13160 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
13161 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
13162 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
13163 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
13164 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
13167 /* store event and trigger custom processing */
13168 stream->pending_event =
13169 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
13171 /* Generic codec_data handler puts it on the caps */
13178 case SL_CONFIG_DESC_TAG:
13179 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
13183 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
13185 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
13191 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
13192 * in use, and should also be used to override some other parameters for some
13194 switch (object_type_id) {
13195 case 0x20: /* MPEG-4 */
13196 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
13197 * profile_and_level_indication */
13198 if (data_ptr != NULL && data_len >= 5 &&
13199 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
13200 gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
13201 data_ptr + 4, data_len - 4);
13203 break; /* Nothing special needed here */
13204 case 0x21: /* H.264 */
13205 codec_name = "H.264 / AVC";
13206 caps = gst_caps_new_simple ("video/x-h264",
13207 "stream-format", G_TYPE_STRING, "avc",
13208 "alignment", G_TYPE_STRING, "au", NULL);
13210 case 0x40: /* AAC (any) */
13211 case 0x66: /* AAC Main */
13212 case 0x67: /* AAC LC */
13213 case 0x68: /* AAC SSR */
13214 /* Override channels and rate based on the codec_data, as it's often
13216 /* Only do so for basic setup without HE-AAC extension */
13217 if (data_ptr && data_len == 2) {
13218 guint channels, rate;
13220 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
13222 stream->n_channels = channels;
13224 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
13226 stream->rate = rate;
13229 /* Set level and profile if possible */
13230 if (data_ptr != NULL && data_len >= 2) {
13231 gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
13232 data_ptr, data_len);
13234 const gchar *profile_str = NULL;
13237 guint8 *codec_data;
13238 gint rate_idx, profile;
13240 /* No codec_data, let's invent something.
13241 * FIXME: This is wrong for SBR! */
13243 GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
13245 buffer = gst_buffer_new_and_alloc (2);
13246 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
13247 codec_data = map.data;
13250 gst_codec_utils_aac_get_index_from_sample_rate (stream->rate);
13252 switch (object_type_id) {
13254 profile_str = "main";
13258 profile_str = "lc";
13262 profile_str = "ssr";
13270 codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
13271 codec_data[1] = ((rate_idx & 0x1) << 7) | (stream->n_channels << 3);
13273 gst_buffer_unmap (buffer, &map);
13274 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
13276 gst_buffer_unref (buffer);
13279 gst_caps_set_simple (stream->caps, "profile", G_TYPE_STRING,
13280 profile_str, NULL);
13284 case 0x60: /* MPEG-2, various profiles */
13290 codec_name = "MPEG-2 video";
13291 caps = gst_caps_new_simple ("video/mpeg",
13292 "mpegversion", G_TYPE_INT, 2,
13293 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13295 case 0x69: /* MPEG-2 BC audio */
13296 case 0x6B: /* MPEG-1 audio */
13297 caps = gst_caps_new_simple ("audio/mpeg",
13298 "mpegversion", G_TYPE_INT, 1, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
13299 codec_name = "MPEG-1 audio";
13301 case 0x6A: /* MPEG-1 */
13302 codec_name = "MPEG-1 video";
13303 caps = gst_caps_new_simple ("video/mpeg",
13304 "mpegversion", G_TYPE_INT, 1,
13305 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13307 case 0x6C: /* MJPEG */
13309 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13311 codec_name = "Motion-JPEG";
13313 case 0x6D: /* PNG */
13315 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
13317 codec_name = "PNG still images";
13319 case 0x6E: /* JPEG2000 */
13320 codec_name = "JPEG-2000";
13321 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
13323 case 0xA4: /* Dirac */
13324 codec_name = "Dirac";
13325 caps = gst_caps_new_empty_simple ("video/x-dirac");
13327 case 0xA5: /* AC3 */
13328 codec_name = "AC-3 audio";
13329 caps = gst_caps_new_simple ("audio/x-ac3",
13330 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13332 case 0xA9: /* AC3 */
13333 codec_name = "DTS audio";
13334 caps = gst_caps_new_simple ("audio/x-dts",
13335 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13337 case 0xE1: /* QCELP */
13338 /* QCELP, the codec_data is a riff tag (little endian) with
13339 * 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). */
13340 caps = gst_caps_new_empty_simple ("audio/qcelp");
13341 codec_name = "QCELP";
13347 /* If we have a replacement caps, then change our caps for this stream */
13349 gst_caps_unref (stream->caps);
13350 stream->caps = caps;
13353 if (codec_name && list)
13354 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
13355 GST_TAG_AUDIO_CODEC, codec_name, NULL);
13357 /* Add the codec_data attribute to caps, if we have it */
13361 buffer = gst_buffer_new_and_alloc (data_len);
13362 gst_buffer_fill (buffer, 0, data_ptr, data_len);
13364 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
13365 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
13367 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
13369 gst_buffer_unref (buffer);
13374 static inline GstCaps *
13375 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
13379 char *s, fourstr[5];
13381 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13382 for (i = 0; i < 4; i++) {
13383 if (!g_ascii_isalnum (fourstr[i]))
13386 s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
13387 caps = gst_caps_new_empty_simple (s);
13392 #define _codec(name) \
13394 if (codec_name) { \
13395 *codec_name = g_strdup (name); \
13400 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13401 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
13403 GstCaps *caps = NULL;
13404 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
13407 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
13408 _codec ("PNG still images");
13409 caps = gst_caps_new_empty_simple ("image/png");
13412 _codec ("JPEG still images");
13414 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13417 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
13418 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
13419 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
13420 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
13421 _codec ("Motion-JPEG");
13423 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13426 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
13427 _codec ("Motion-JPEG format B");
13428 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
13431 _codec ("JPEG-2000");
13432 /* override to what it should be according to spec, avoid palette_data */
13433 stream->bits_per_sample = 24;
13434 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
13437 _codec ("Sorensen video v.3");
13438 caps = gst_caps_new_simple ("video/x-svq",
13439 "svqversion", G_TYPE_INT, 3, NULL);
13441 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
13442 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
13443 _codec ("Sorensen video v.1");
13444 caps = gst_caps_new_simple ("video/x-svq",
13445 "svqversion", G_TYPE_INT, 1, NULL);
13447 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
13448 caps = gst_caps_new_empty_simple ("video/x-raw");
13449 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
13450 _codec ("Windows Raw RGB");
13451 stream->alignment = 32;
13457 bps = QT_UINT16 (stsd_data + 98);
13460 format = GST_VIDEO_FORMAT_RGB15;
13463 format = GST_VIDEO_FORMAT_RGB16;
13466 format = GST_VIDEO_FORMAT_RGB;
13469 format = GST_VIDEO_FORMAT_ARGB;
13477 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
13478 format = GST_VIDEO_FORMAT_I420;
13480 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
13481 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
13482 format = GST_VIDEO_FORMAT_I420;
13485 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
13486 format = GST_VIDEO_FORMAT_UYVY;
13488 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
13489 format = GST_VIDEO_FORMAT_v308;
13491 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
13492 format = GST_VIDEO_FORMAT_v216;
13495 format = GST_VIDEO_FORMAT_v210;
13497 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
13498 format = GST_VIDEO_FORMAT_r210;
13500 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
13501 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
13502 format = GST_VIDEO_FORMAT_v410;
13505 /* Packed YUV 4:4:4:4 8 bit in 32 bits
13506 * but different order than AYUV
13507 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
13508 format = GST_VIDEO_FORMAT_v408;
13511 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
13512 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
13513 _codec ("MPEG-1 video");
13514 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
13515 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13517 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
13518 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
13519 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
13520 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
13521 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
13522 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
13523 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
13524 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
13525 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
13526 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
13527 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
13528 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
13529 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
13530 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
13531 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
13532 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
13533 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
13534 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
13535 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
13536 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
13537 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
13538 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
13539 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
13540 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
13541 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
13542 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
13543 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
13544 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
13545 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
13546 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
13547 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
13548 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
13549 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
13550 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
13551 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
13552 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
13553 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
13554 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
13555 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
13556 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
13557 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
13558 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
13559 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
13560 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
13561 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
13562 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
13563 case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
13564 _codec ("MPEG-2 video");
13565 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
13566 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13568 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
13569 _codec ("GIF still images");
13570 caps = gst_caps_new_empty_simple ("image/gif");
13573 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
13575 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
13577 /* ffmpeg uses the height/width props, don't know why */
13578 caps = gst_caps_new_simple ("video/x-h263",
13579 "variant", G_TYPE_STRING, "itu", NULL);
13583 _codec ("MPEG-4 video");
13584 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
13585 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13587 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
13588 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
13589 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
13590 caps = gst_caps_new_simple ("video/x-msmpeg",
13591 "msmpegversion", G_TYPE_INT, 43, NULL);
13593 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
13595 caps = gst_caps_new_simple ("video/x-divx",
13596 "divxversion", G_TYPE_INT, 3, NULL);
13598 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
13599 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
13601 caps = gst_caps_new_simple ("video/x-divx",
13602 "divxversion", G_TYPE_INT, 4, NULL);
13604 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
13606 caps = gst_caps_new_simple ("video/x-divx",
13607 "divxversion", G_TYPE_INT, 5, NULL);
13610 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
13612 caps = gst_caps_new_simple ("video/x-ffv",
13613 "ffvversion", G_TYPE_INT, 1, NULL);
13616 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
13617 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
13622 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
13623 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
13624 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13628 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
13629 _codec ("Cinepak");
13630 caps = gst_caps_new_empty_simple ("video/x-cinepak");
13632 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
13633 _codec ("Apple QuickDraw");
13634 caps = gst_caps_new_empty_simple ("video/x-qdrw");
13636 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
13637 _codec ("Apple video");
13638 caps = gst_caps_new_empty_simple ("video/x-apple-video");
13642 _codec ("H.264 / AVC");
13643 caps = gst_caps_new_simple ("video/x-h264",
13644 "stream-format", G_TYPE_STRING, "avc",
13645 "alignment", G_TYPE_STRING, "au", NULL);
13648 _codec ("H.264 / AVC");
13649 caps = gst_caps_new_simple ("video/x-h264",
13650 "stream-format", G_TYPE_STRING, "avc3",
13651 "alignment", G_TYPE_STRING, "au", NULL);
13655 _codec ("H.265 / HEVC");
13656 caps = gst_caps_new_simple ("video/x-h265",
13657 "stream-format", G_TYPE_STRING, "hvc1",
13658 "alignment", G_TYPE_STRING, "au", NULL);
13661 _codec ("H.265 / HEVC");
13662 caps = gst_caps_new_simple ("video/x-h265",
13663 "stream-format", G_TYPE_STRING, "hev1",
13664 "alignment", G_TYPE_STRING, "au", NULL);
13667 _codec ("Run-length encoding");
13668 caps = gst_caps_new_simple ("video/x-rle",
13669 "layout", G_TYPE_STRING, "quicktime", NULL);
13672 _codec ("Run-length encoding");
13673 caps = gst_caps_new_simple ("video/x-rle",
13674 "layout", G_TYPE_STRING, "microsoft", NULL);
13676 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
13677 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
13678 _codec ("Indeo Video 3");
13679 caps = gst_caps_new_simple ("video/x-indeo",
13680 "indeoversion", G_TYPE_INT, 3, NULL);
13682 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
13683 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
13684 _codec ("Intel Video 4");
13685 caps = gst_caps_new_simple ("video/x-indeo",
13686 "indeoversion", G_TYPE_INT, 4, NULL);
13690 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
13691 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
13692 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
13693 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
13694 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
13695 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
13696 _codec ("DV Video");
13697 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
13698 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13700 case FOURCC_dv5n: /* DVCPRO50 NTSC */
13701 case FOURCC_dv5p: /* DVCPRO50 PAL */
13702 _codec ("DVCPro50 Video");
13703 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
13704 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13706 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
13707 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
13708 _codec ("DVCProHD Video");
13709 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
13710 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13712 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
13713 _codec ("Apple Graphics (SMC)");
13714 caps = gst_caps_new_empty_simple ("video/x-smc");
13716 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
13718 caps = gst_caps_new_empty_simple ("video/x-vp3");
13720 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
13721 _codec ("VP6 Flash");
13722 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
13726 caps = gst_caps_new_empty_simple ("video/x-theora");
13727 /* theora uses one byte of padding in the data stream because it does not
13728 * allow 0 sized packets while theora does */
13729 stream->padding = 1;
13733 caps = gst_caps_new_empty_simple ("video/x-dirac");
13735 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
13736 _codec ("TIFF still images");
13737 caps = gst_caps_new_empty_simple ("image/tiff");
13739 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
13740 _codec ("Apple Intermediate Codec");
13741 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
13743 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
13744 _codec ("AVID DNxHD");
13745 caps = gst_caps_from_string ("video/x-dnxhd");
13748 _codec ("On2 VP8");
13749 caps = gst_caps_from_string ("video/x-vp8");
13752 _codec ("Apple ProRes LT");
13754 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
13758 _codec ("Apple ProRes HQ");
13760 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
13764 _codec ("Apple ProRes");
13766 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13770 _codec ("Apple ProRes Proxy");
13772 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13776 _codec ("Apple ProRes 4444");
13778 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13782 _codec ("Apple ProRes 4444 XQ");
13784 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13788 _codec ("GoPro CineForm");
13789 caps = gst_caps_from_string ("video/x-cineform");
13794 caps = gst_caps_new_simple ("video/x-wmv",
13795 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
13797 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
13800 caps = _get_unknown_codec_name ("video", fourcc);
13805 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
13808 gst_video_info_init (&info);
13809 gst_video_info_set_format (&info, format, stream->width, stream->height);
13811 caps = gst_video_info_to_caps (&info);
13812 *codec_name = gst_pb_utils_get_codec_description (caps);
13814 /* enable clipping for raw video streams */
13815 stream->need_clip = TRUE;
13816 stream->alignment = 32;
13823 round_up_pow2 (guint n)
13835 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13836 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
13839 const GstStructure *s;
13842 GstAudioFormat format = 0;
13845 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
13847 depth = stream->bytes_per_packet * 8;
13850 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
13852 /* 8-bit audio is unsigned */
13854 format = GST_AUDIO_FORMAT_U8;
13855 /* otherwise it's signed and big-endian just like 'twos' */
13857 endian = G_BIG_ENDIAN;
13864 endian = G_LITTLE_ENDIAN;
13867 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
13869 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
13873 caps = gst_caps_new_simple ("audio/x-raw",
13874 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
13875 "layout", G_TYPE_STRING, "interleaved", NULL);
13876 stream->alignment = GST_ROUND_UP_8 (depth);
13877 stream->alignment = round_up_pow2 (stream->alignment);
13880 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
13881 _codec ("Raw 64-bit floating-point audio");
13882 caps = gst_caps_new_simple ("audio/x-raw",
13883 "format", G_TYPE_STRING, "F64BE",
13884 "layout", G_TYPE_STRING, "interleaved", NULL);
13885 stream->alignment = 8;
13887 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
13888 _codec ("Raw 32-bit floating-point audio");
13889 caps = gst_caps_new_simple ("audio/x-raw",
13890 "format", G_TYPE_STRING, "F32BE",
13891 "layout", G_TYPE_STRING, "interleaved", NULL);
13892 stream->alignment = 4;
13895 _codec ("Raw 24-bit PCM audio");
13896 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
13898 caps = gst_caps_new_simple ("audio/x-raw",
13899 "format", G_TYPE_STRING, "S24BE",
13900 "layout", G_TYPE_STRING, "interleaved", NULL);
13901 stream->alignment = 4;
13903 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
13904 _codec ("Raw 32-bit PCM audio");
13905 caps = gst_caps_new_simple ("audio/x-raw",
13906 "format", G_TYPE_STRING, "S32BE",
13907 "layout", G_TYPE_STRING, "interleaved", NULL);
13908 stream->alignment = 4;
13910 case GST_MAKE_FOURCC ('s', '1', '6', 'l'):
13911 _codec ("Raw 16-bit PCM audio");
13912 caps = gst_caps_new_simple ("audio/x-raw",
13913 "format", G_TYPE_STRING, "S16LE",
13914 "layout", G_TYPE_STRING, "interleaved", NULL);
13915 stream->alignment = 2;
13918 _codec ("Mu-law audio");
13919 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
13922 _codec ("A-law audio");
13923 caps = gst_caps_new_empty_simple ("audio/x-alaw");
13927 _codec ("Microsoft ADPCM");
13928 /* Microsoft ADPCM-ACM code 2 */
13929 caps = gst_caps_new_simple ("audio/x-adpcm",
13930 "layout", G_TYPE_STRING, "microsoft", NULL);
13934 _codec ("DVI/IMA ADPCM");
13935 caps = gst_caps_new_simple ("audio/x-adpcm",
13936 "layout", G_TYPE_STRING, "dvi", NULL);
13940 _codec ("DVI/Intel IMA ADPCM");
13941 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
13942 caps = gst_caps_new_simple ("audio/x-adpcm",
13943 "layout", G_TYPE_STRING, "quicktime", NULL);
13947 /* MPEG layer 3, CBR only (pre QT4.1) */
13949 _codec ("MPEG-1 layer 3");
13950 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
13951 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
13952 "mpegversion", G_TYPE_INT, 1, NULL);
13954 case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
13955 _codec ("MPEG-1 layer 2");
13957 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
13958 "mpegversion", G_TYPE_INT, 1, NULL);
13961 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
13962 _codec ("EAC-3 audio");
13963 caps = gst_caps_new_simple ("audio/x-eac3",
13964 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13965 stream->sampled = TRUE;
13967 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
13969 _codec ("AC-3 audio");
13970 caps = gst_caps_new_simple ("audio/x-ac3",
13971 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13972 stream->sampled = TRUE;
13974 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
13975 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
13976 _codec ("DTS audio");
13977 caps = gst_caps_new_simple ("audio/x-dts",
13978 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13979 stream->sampled = TRUE;
13981 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
13982 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
13983 _codec ("DTS-HD audio");
13984 caps = gst_caps_new_simple ("audio/x-dts",
13985 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13986 stream->sampled = TRUE;
13990 caps = gst_caps_new_simple ("audio/x-mace",
13991 "maceversion", G_TYPE_INT, 3, NULL);
13995 caps = gst_caps_new_simple ("audio/x-mace",
13996 "maceversion", G_TYPE_INT, 6, NULL);
13998 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
14000 caps = gst_caps_new_empty_simple ("application/ogg");
14002 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
14003 _codec ("DV audio");
14004 caps = gst_caps_new_empty_simple ("audio/x-dv");
14007 _codec ("MPEG-4 AAC audio");
14008 caps = gst_caps_new_simple ("audio/mpeg",
14009 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
14010 "stream-format", G_TYPE_STRING, "raw", NULL);
14012 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
14013 _codec ("QDesign Music");
14014 caps = gst_caps_new_empty_simple ("audio/x-qdm");
14017 _codec ("QDesign Music v.2");
14018 /* FIXME: QDesign music version 2 (no constant) */
14019 if (FALSE && data) {
14020 caps = gst_caps_new_simple ("audio/x-qdm2",
14021 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
14022 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
14023 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
14025 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
14029 _codec ("GSM audio");
14030 caps = gst_caps_new_empty_simple ("audio/x-gsm");
14033 _codec ("AMR audio");
14034 caps = gst_caps_new_empty_simple ("audio/AMR");
14037 _codec ("AMR-WB audio");
14038 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
14041 _codec ("Quicktime IMA ADPCM");
14042 caps = gst_caps_new_simple ("audio/x-adpcm",
14043 "layout", G_TYPE_STRING, "quicktime", NULL);
14046 _codec ("Apple lossless audio");
14047 caps = gst_caps_new_empty_simple ("audio/x-alac");
14050 _codec ("Free Lossless Audio Codec");
14051 caps = gst_caps_new_simple ("audio/x-flac",
14052 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14054 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
14055 _codec ("QualComm PureVoice");
14056 caps = gst_caps_from_string ("audio/qcelp");
14061 caps = gst_caps_new_empty_simple ("audio/x-wma");
14065 caps = gst_caps_new_empty_simple ("audio/x-opus");
14067 case GST_MAKE_FOURCC ('l', 'p', 'c', 'm'):
14072 GstAudioFormat format;
14075 FLAG_IS_FLOAT = 0x1,
14076 FLAG_IS_BIG_ENDIAN = 0x2,
14077 FLAG_IS_SIGNED = 0x4,
14078 FLAG_IS_PACKED = 0x8,
14079 FLAG_IS_ALIGNED_HIGH = 0x10,
14080 FLAG_IS_NON_INTERLEAVED = 0x20
14082 _codec ("Raw LPCM audio");
14084 if (data && len >= 56) {
14085 depth = QT_UINT32 (data + 40);
14086 flags = QT_UINT32 (data + 44);
14087 width = QT_UINT32 (data + 48) * 8 / stream->n_channels;
14089 if ((flags & FLAG_IS_FLOAT) == 0) {
14094 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
14095 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
14096 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
14097 caps = gst_caps_new_simple ("audio/x-raw",
14098 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14099 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
14100 "non-interleaved" : "interleaved", NULL);
14101 stream->alignment = GST_ROUND_UP_8 (depth);
14102 stream->alignment = round_up_pow2 (stream->alignment);
14107 if (flags & FLAG_IS_BIG_ENDIAN)
14108 format = GST_AUDIO_FORMAT_F64BE;
14110 format = GST_AUDIO_FORMAT_F64LE;
14112 if (flags & FLAG_IS_BIG_ENDIAN)
14113 format = GST_AUDIO_FORMAT_F32BE;
14115 format = GST_AUDIO_FORMAT_F32LE;
14117 caps = gst_caps_new_simple ("audio/x-raw",
14118 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14119 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
14120 "non-interleaved" : "interleaved", NULL);
14121 stream->alignment = width / 8;
14125 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
14129 caps = _get_unknown_codec_name ("audio", fourcc);
14135 GstCaps *templ_caps =
14136 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
14137 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
14138 gst_caps_unref (caps);
14139 gst_caps_unref (templ_caps);
14140 caps = intersection;
14143 /* enable clipping for raw audio streams */
14144 s = gst_caps_get_structure (caps, 0);
14145 name = gst_structure_get_name (s);
14146 if (g_str_has_prefix (name, "audio/x-raw")) {
14147 stream->need_clip = TRUE;
14148 stream->max_buffer_size = 4096 * stream->bytes_per_frame;
14149 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
14155 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14156 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
14160 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14164 _codec ("DVD subtitle");
14165 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
14166 stream->need_process = TRUE;
14169 _codec ("Quicktime timed text");
14172 _codec ("3GPP timed text");
14174 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
14176 /* actual text piece needs to be extracted */
14177 stream->need_process = TRUE;
14180 _codec ("XML subtitles");
14181 caps = gst_caps_new_empty_simple ("application/ttml+xml");
14185 caps = _get_unknown_codec_name ("text", fourcc);
14193 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14194 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
14200 _codec ("MPEG 1 video");
14201 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14202 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14212 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
14213 const gchar * system_id)
14217 if (!qtdemux->protection_system_ids)
14218 qtdemux->protection_system_ids =
14219 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
14220 /* Check whether we already have an entry for this system ID. */
14221 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
14222 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
14223 if (g_ascii_strcasecmp (system_id, id) == 0) {
14227 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
14228 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,