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.
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Library General Public
15 * License as published by the Free Software Foundation; either
16 * version 2 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Library General Public License for more details.
23 * You should have received a copy of the GNU Library General Public
24 * License along with this library; if not, write to the
25 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
26 * Boston, MA 02110-1301, USA.
30 * SECTION:element-qtdemux
32 * Demuxes a .mov file into raw or compressed audio and/or video streams.
34 * This element supports both push and pull-based scheduling, depending on the
35 * capabilities of the upstream elements.
38 * <title>Example launch line</title>
40 * 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
41 * ]| Play (parse and decode) a .mov file and try to output it to
42 * an automatically detected soundcard and videosink. If the MOV file contains
43 * compressed audio or video data, this will only work if you have the
44 * right decoder elements/plugins installed.
52 #include "gst/gst-i18n-plugin.h"
54 #include <glib/gprintf.h>
55 #include <gst/tag/tag.h>
56 #include <gst/audio/audio.h>
57 #include <gst/video/video.h>
59 #include "qtatomparser.h"
60 #include "qtdemux_types.h"
61 #include "qtdemux_dump.h"
63 #include "descriptors.h"
64 #include "qtdemux_lang.h"
66 #include "qtpalette.h"
68 #include "gst/riff/riff-media.h"
69 #include "gst/riff/riff-read.h"
71 #include <gst/pbutils/pbutils.h>
78 #include <gst/math-compat.h>
84 /* max. size considered 'sane' for non-mdat atoms */
85 #define QTDEMUX_MAX_ATOM_SIZE (25*1024*1024)
87 /* if the sample index is larger than this, something is likely wrong */
88 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (50*1024*1024)
90 /* For converting qt creation times to unix epoch times */
91 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
92 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
93 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
94 QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
96 #define STREAM_IS_EOS(s) (s->time_position == GST_CLOCK_TIME_NONE)
98 GST_DEBUG_CATEGORY (qtdemux_debug);
100 /*typedef struct _QtNode QtNode; */
101 typedef struct _QtDemuxSegment QtDemuxSegment;
102 typedef struct _QtDemuxSample QtDemuxSample;
104 typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo;
113 struct _QtDemuxSample
116 gint32 pts_offset; /* Add this value to timestamp to get the pts */
118 guint64 timestamp; /* DTS In mov time */
119 guint32 duration; /* In mov time */
120 gboolean keyframe; /* TRUE when this packet is a keyframe */
123 /* Macros for converting to/from timescale */
124 #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale))
125 #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND))
127 #define QTTIME_TO_GSTTIME(qtdemux, value) (gst_util_uint64_scale((value), GST_SECOND, (qtdemux)->timescale))
128 #define GSTTIME_TO_QTTIME(qtdemux, value) (gst_util_uint64_scale((value), (qtdemux)->timescale, GST_SECOND))
130 /* timestamp is the DTS */
131 #define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp))
132 /* timestamp + offset is the PTS */
133 #define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (stream)->cslg_shift + (sample)->pts_offset))
134 /* timestamp + duration - dts is the duration */
135 #define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts))
137 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
140 * Quicktime has tracks and segments. A track is a continuous piece of
141 * multimedia content. The track is not always played from start to finish but
142 * instead, pieces of the track are 'cut out' and played in sequence. This is
143 * what the segments do.
145 * Inside the track we have keyframes (K) and delta frames. The track has its
146 * own timing, which starts from 0 and extends to end. The position in the track
147 * is called the media_time.
149 * The segments now describe the pieces that should be played from this track
150 * and are basically tuples of media_time/duration/rate entries. We can have
151 * multiple segments and they are all played after one another. An example:
153 * segment 1: media_time: 1 second, duration: 1 second, rate 1
154 * segment 2: media_time: 3 second, duration: 2 second, rate 2
156 * To correctly play back this track, one must play: 1 second of media starting
157 * from media_time 1 followed by 2 seconds of media starting from media_time 3
160 * Each of the segments will be played at a specific time, the first segment at
161 * time 0, the second one after the duration of the first one, etc.. Note that
162 * the time in resulting playback is not identical to the media_time of the
165 * Visually, assuming the track has 4 second of media_time:
168 * .-----------------------------------------------------------.
169 * track: | K.....K.........K........K.......K.......K...........K... |
170 * '-----------------------------------------------------------'
172 * .------------^ ^ .----------^ ^
173 * / .-------------' / .------------------'
175 * .--------------. .--------------.
176 * | segment 1 | | segment 2 |
177 * '--------------' '--------------'
179 * The challenge here is to cut out the right pieces of the track for each of
180 * the playback segments. This fortunately can easily be done with the SEGMENT
181 * events of GStreamer.
183 * For playback of segment 1, we need to provide the decoder with the keyframe
184 * (a), in the above figure, but we must instruct it only to output the decoded
185 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
186 * position set to the time of the segment: 0.
188 * We then proceed to push data from keyframe (a) to frame (b). The decoder
189 * decodes but clips all before media_time 1.
191 * After finishing a segment, we push out a new SEGMENT event with the clipping
192 * boundaries of the new data.
194 * This is a good usecase for the GStreamer accumulated SEGMENT events.
197 struct _QtDemuxSegment
199 /* global time and duration, all gst time */
201 GstClockTime stop_time;
202 GstClockTime duration;
203 /* media time of trak, all gst time */
204 GstClockTime media_start;
205 GstClockTime media_stop;
207 /* Media start time in trak timescale units */
208 guint32 trak_media_start;
211 #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
213 /* Used with fragmented MP4 files (mfra atom) */
218 } QtDemuxRandomAccessEntry;
220 struct _QtDemuxStream
231 gboolean new_stream; /* signals that a stream_start is required */
232 gboolean on_keyframe; /* if this stream last pushed buffer was a
233 * keyframe. This is important to identify
234 * where to stop pushing buffers after a
235 * segment stop time */
237 /* if the stream has a redirect URI in its headers, we store it here */
244 guint64 duration; /* in timescale */
248 gchar lang_id[4]; /* ISO 639-2T language code */
252 QtDemuxSample *samples;
253 gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */
254 guint32 first_duration; /* duration in timescale of first sample, used for figuring out
255 the framerate, in timescale units */
256 guint32 offset_in_sample;
257 guint32 max_buffer_size;
259 /* if we use chunks or samples */
271 /* Numerator/denominator framerate */
274 guint16 bits_per_sample;
275 guint16 color_table_id;
276 GstMemory *rgb8_palette;
281 guint samples_per_packet;
282 guint samples_per_frame;
283 guint bytes_per_packet;
284 guint bytes_per_sample;
285 guint bytes_per_frame;
289 gboolean use_allocator;
290 GstAllocator *allocator;
291 GstAllocationParams params;
293 /* when a discontinuity is pending */
296 /* list of buffers to push first */
299 /* if we need to clip this buffer. This is only needed for uncompressed
303 /* buffer needs some custom processing, e.g. subtitles */
304 gboolean need_process;
306 /* current position */
307 guint32 segment_index;
308 guint32 sample_index;
309 GstClockTime time_position; /* in gst time */
310 guint64 accumulated_base;
312 /* the Gst segment we are processing out, used for clipping */
314 guint32 segment_seqnum; /* segment event seqnum obtained from seek */
316 /* quicktime segments */
318 QtDemuxSegment *segments;
319 gboolean dummy_segment;
324 GstTagList *pending_tags;
325 gboolean send_global_tags;
327 GstEvent *pending_event;
337 gboolean chunks_are_samples; /* TRUE means treat chunks as samples */
341 GstByteReader co_chunk;
343 guint32 current_chunk;
345 guint32 samples_per_chunk;
346 guint32 stco_sample_index;
348 guint32 sample_size; /* 0 means variable sizes are stored in stsz */
351 guint32 n_samples_per_chunk;
352 guint32 stsc_chunk_index;
353 guint32 stsc_sample_index;
354 guint64 chunk_offset;
357 guint32 stts_samples;
358 guint32 n_sample_times;
359 guint32 stts_sample_index;
361 guint32 stts_duration;
363 gboolean stss_present;
364 guint32 n_sample_syncs;
367 gboolean stps_present;
368 guint32 n_sample_partial_syncs;
370 QtDemuxRandomAccessEntry *ra_entries;
373 const QtDemuxRandomAccessEntry *pending_seek;
376 gboolean ctts_present;
377 guint32 n_composition_times;
379 guint32 ctts_sample_index;
387 gboolean parsed_trex;
388 guint32 def_sample_duration;
389 guint32 def_sample_size;
390 guint32 def_sample_flags;
394 /* stereoscopic video streams */
395 GstVideoMultiviewMode multiview_mode;
396 GstVideoMultiviewFlags multiview_flags;
398 /* protected streams */
400 guint32 protection_scheme_type;
401 guint32 protection_scheme_version;
402 gpointer protection_scheme_info; /* specific to the protection scheme */
403 GQueue protection_scheme_event_queue;
406 /* Contains properties and cryptographic info for a set of samples from a
407 * track protected using Common Encryption (cenc) */
408 struct _QtDemuxCencSampleSetInfo
410 GstStructure *default_properties;
412 /* @crypto_info holds one GstStructure per sample */
413 GPtrArray *crypto_info;
418 QTDEMUX_STATE_INITIAL, /* Initial state (haven't got the header yet) */
419 QTDEMUX_STATE_HEADER, /* Parsing the header */
420 QTDEMUX_STATE_MOVIE, /* Parsing/Playing the media data */
421 QTDEMUX_STATE_BUFFER_MDAT /* Buffering the mdat atom */
424 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
425 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
426 guint32 fourcc, GstByteReader * parser);
427 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
428 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
429 guint32 fourcc, GstByteReader * parser);
431 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
433 static GstStaticPadTemplate gst_qtdemux_sink_template =
434 GST_STATIC_PAD_TEMPLATE ("sink",
437 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
441 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
442 GST_STATIC_PAD_TEMPLATE ("video_%u",
445 GST_STATIC_CAPS_ANY);
447 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
448 GST_STATIC_PAD_TEMPLATE ("audio_%u",
451 GST_STATIC_CAPS_ANY);
453 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
454 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
457 GST_STATIC_CAPS_ANY);
459 #define gst_qtdemux_parent_class parent_class
460 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
462 static void gst_qtdemux_dispose (GObject * object);
465 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
466 GstClockTime media_time);
468 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
469 QtDemuxStream * str, gint64 media_offset);
472 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
473 static GstIndex *gst_qtdemux_get_index (GstElement * element);
475 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
476 GstStateChange transition);
477 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
478 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
479 GstObject * parent, GstPadMode mode, gboolean active);
481 static void gst_qtdemux_loop (GstPad * pad);
482 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
484 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
486 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
487 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
488 QtDemuxStream * stream);
489 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
492 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
493 const guint8 * buffer, guint length);
494 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
495 const guint8 * buffer, guint length);
496 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
497 static void qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist,
500 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
501 QtDemuxStream * stream, GNode * esds, GstTagList * list);
502 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
503 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
504 gchar ** codec_name);
505 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
506 QtDemuxStream * stream, guint32 fourcc, const guint8 * data, int len,
507 gchar ** codec_name);
508 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux,
509 QtDemuxStream * stream, guint32 fourcc, const guint8 * data,
510 gchar ** codec_name);
511 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
512 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
513 gchar ** codec_name);
515 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
516 QtDemuxStream * stream, guint32 n);
517 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
518 static void gst_qtdemux_stream_free (GstQTDemux * qtdemux,
519 QtDemuxStream * stream);
520 static void gst_qtdemux_stream_clear (GstQTDemux * qtdemux,
521 QtDemuxStream * stream);
522 static void gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int index);
523 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
524 static void qtdemux_do_allocation (GstQTDemux * qtdemux,
525 QtDemuxStream * stream);
527 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
528 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
530 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
534 gst_qtdemux_class_init (GstQTDemuxClass * klass)
536 GObjectClass *gobject_class;
537 GstElementClass *gstelement_class;
539 gobject_class = (GObjectClass *) klass;
540 gstelement_class = (GstElementClass *) klass;
542 parent_class = g_type_class_peek_parent (klass);
544 gobject_class->dispose = gst_qtdemux_dispose;
546 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
548 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
549 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
552 gst_tag_register_musicbrainz_tags ();
554 gst_element_class_add_pad_template (gstelement_class,
555 gst_static_pad_template_get (&gst_qtdemux_sink_template));
556 gst_element_class_add_pad_template (gstelement_class,
557 gst_static_pad_template_get (&gst_qtdemux_videosrc_template));
558 gst_element_class_add_pad_template (gstelement_class,
559 gst_static_pad_template_get (&gst_qtdemux_audiosrc_template));
560 gst_element_class_add_pad_template (gstelement_class,
561 gst_static_pad_template_get (&gst_qtdemux_subsrc_template));
562 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
564 "Demultiplex a QuickTime file into audio and video streams",
565 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
567 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
572 gst_qtdemux_init (GstQTDemux * qtdemux)
575 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
576 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
577 gst_pad_set_activatemode_function (qtdemux->sinkpad,
578 qtdemux_sink_activate_mode);
579 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
580 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
581 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
583 qtdemux->state = QTDEMUX_STATE_INITIAL;
584 qtdemux->pullbased = FALSE;
585 qtdemux->posted_redirect = FALSE;
586 qtdemux->neededbytes = 16;
588 qtdemux->adapter = gst_adapter_new ();
590 qtdemux->first_mdat = -1;
591 qtdemux->got_moov = FALSE;
592 qtdemux->mdatoffset = -1;
593 qtdemux->mdatbuffer = NULL;
594 qtdemux->restoredata_buffer = NULL;
595 qtdemux->restoredata_offset = -1;
596 qtdemux->fragment_start = -1;
597 qtdemux->fragment_start_offset = -1;
598 qtdemux->media_caps = NULL;
599 qtdemux->exposed = FALSE;
600 qtdemux->mss_mode = FALSE;
601 qtdemux->pending_newsegment = NULL;
602 qtdemux->upstream_format_is_time = FALSE;
603 qtdemux->have_group_id = FALSE;
604 qtdemux->group_id = G_MAXUINT;
605 qtdemux->cenc_aux_info_offset = 0;
606 qtdemux->cenc_aux_info_sizes = NULL;
607 qtdemux->cenc_aux_sample_count = 0;
608 qtdemux->protection_system_ids = NULL;
609 g_queue_init (&qtdemux->protection_event_queue);
610 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
611 qtdemux->flowcombiner = gst_flow_combiner_new ();
613 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
617 gst_qtdemux_dispose (GObject * object)
619 GstQTDemux *qtdemux = GST_QTDEMUX (object);
621 if (qtdemux->adapter) {
622 g_object_unref (G_OBJECT (qtdemux->adapter));
623 qtdemux->adapter = NULL;
625 gst_flow_combiner_free (qtdemux->flowcombiner);
626 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
628 g_queue_clear (&qtdemux->protection_event_queue);
630 g_free (qtdemux->cenc_aux_info_sizes);
631 qtdemux->cenc_aux_info_sizes = NULL;
633 G_OBJECT_CLASS (parent_class)->dispose (object);
637 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
639 if (qtdemux->posted_redirect) {
640 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
641 (_("This file contains no playable streams.")),
642 ("no known streams found, a redirect message has been posted"));
644 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
645 (_("This file contains no playable streams.")),
646 ("no known streams found"));
651 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
653 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
654 mem, size, 0, size, mem, free_func);
658 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
665 if (G_UNLIKELY (size == 0)) {
667 GstBuffer *tmp = NULL;
669 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
670 if (ret != GST_FLOW_OK)
673 gst_buffer_map (tmp, &map, GST_MAP_READ);
674 size = QT_UINT32 (map.data);
675 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
677 gst_buffer_unmap (tmp, &map);
678 gst_buffer_unref (tmp);
681 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
682 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
683 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
684 /* we're pulling header but already got most interesting bits,
685 * so never mind the rest (e.g. tags) (that much) */
686 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
690 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
691 (_("This file is invalid and cannot be played.")),
692 ("atom has bogus size %" G_GUINT64_FORMAT, size));
693 return GST_FLOW_ERROR;
697 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
699 if (G_UNLIKELY (flow != GST_FLOW_OK))
702 bsize = gst_buffer_get_size (*buf);
703 /* Catch short reads - we don't want any partial atoms */
704 if (G_UNLIKELY (bsize < size)) {
705 GST_WARNING_OBJECT (qtdemux,
706 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
707 gst_buffer_unref (*buf);
717 gst_qtdemux_src_convert (GstPad * pad, GstFormat src_format, gint64 src_value,
718 GstFormat dest_format, gint64 * dest_value)
721 QtDemuxStream *stream = gst_pad_get_element_private (pad);
722 GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
725 if (stream->subtype != FOURCC_vide) {
730 switch (src_format) {
731 case GST_FORMAT_TIME:
732 switch (dest_format) {
733 case GST_FORMAT_BYTES:{
734 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
738 *dest_value = stream->samples[index].offset;
740 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
741 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
742 GST_TIME_ARGS (src_value), *dest_value);
750 case GST_FORMAT_BYTES:
751 switch (dest_format) {
752 case GST_FORMAT_TIME:{
754 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
761 QTSTREAMTIME_TO_GSTTIME (stream,
762 stream->samples[index].timestamp);
763 GST_DEBUG_OBJECT (qtdemux,
764 "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
765 GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
778 gst_object_unref (qtdemux);
785 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
789 *duration = GST_CLOCK_TIME_NONE;
791 if (qtdemux->duration != 0) {
792 if (qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
793 *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
800 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
803 gboolean res = FALSE;
804 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
806 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
808 switch (GST_QUERY_TYPE (query)) {
809 case GST_QUERY_POSITION:{
812 gst_query_parse_position (query, &fmt, NULL);
813 if (fmt == GST_FORMAT_TIME
814 && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
815 gst_query_set_position (query, GST_FORMAT_TIME,
816 qtdemux->segment.position);
821 case GST_QUERY_DURATION:{
824 gst_query_parse_duration (query, &fmt, NULL);
825 if (fmt == GST_FORMAT_TIME) {
826 /* First try to query upstream */
827 res = gst_pad_query_default (pad, parent, query);
830 if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
831 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
838 case GST_QUERY_CONVERT:{
839 GstFormat src_fmt, dest_fmt;
840 gint64 src_value, dest_value = 0;
842 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
844 res = gst_qtdemux_src_convert (pad,
845 src_fmt, src_value, dest_fmt, &dest_value);
847 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
852 case GST_QUERY_FORMATS:
853 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
856 case GST_QUERY_SEEKING:{
860 /* try upstream first */
861 res = gst_pad_query_default (pad, parent, query);
864 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
865 if (fmt == GST_FORMAT_TIME) {
866 GstClockTime duration = GST_CLOCK_TIME_NONE;
868 gst_qtdemux_get_duration (qtdemux, &duration);
870 if (!qtdemux->pullbased) {
873 /* we might be able with help from upstream */
875 q = gst_query_new_seeking (GST_FORMAT_BYTES);
876 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
877 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
878 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
882 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
888 case GST_QUERY_SEGMENT:
893 format = qtdemux->segment.format;
896 gst_segment_to_stream_time (&qtdemux->segment, format,
897 qtdemux->segment.start);
898 if ((stop = qtdemux->segment.stop) == -1)
899 stop = qtdemux->segment.duration;
901 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
903 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
908 res = gst_pad_query_default (pad, parent, query);
916 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
918 if (G_LIKELY (stream->pad)) {
919 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
920 GST_DEBUG_PAD_NAME (stream->pad));
922 if (G_UNLIKELY (stream->pending_tags)) {
923 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
924 stream->pending_tags);
925 gst_pad_push_event (stream->pad,
926 gst_event_new_tag (stream->pending_tags));
927 stream->pending_tags = NULL;
930 if (G_UNLIKELY (stream->send_global_tags && qtdemux->tag_list)) {
931 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
933 gst_pad_push_event (stream->pad,
934 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
935 stream->send_global_tags = FALSE;
940 /* push event on all source pads; takes ownership of the event */
942 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
945 gboolean has_valid_stream = FALSE;
946 GstEventType etype = GST_EVENT_TYPE (event);
948 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
949 GST_EVENT_TYPE_NAME (event));
951 for (n = 0; n < qtdemux->n_streams; n++) {
953 QtDemuxStream *stream = qtdemux->streams[n];
954 GST_DEBUG_OBJECT (qtdemux, "pushing on pad %i", n);
956 if ((pad = stream->pad)) {
957 has_valid_stream = TRUE;
959 if (etype == GST_EVENT_EOS) {
960 /* let's not send twice */
961 if (stream->sent_eos)
963 stream->sent_eos = TRUE;
966 gst_pad_push_event (pad, gst_event_ref (event));
970 gst_event_unref (event);
972 /* if it is EOS and there are no pads, post an error */
973 if (!has_valid_stream && etype == GST_EVENT_EOS) {
974 gst_qtdemux_post_no_playable_stream_error (qtdemux);
978 /* push a pending newsegment event, if any from the streaming thread */
980 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
982 if (qtdemux->pending_newsegment) {
983 gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
984 qtdemux->pending_newsegment = NULL;
994 find_func (QtDemuxSample * s1, guint64 * media_time, gpointer user_data)
996 if (s1->timestamp + s1->pts_offset > *media_time)
1002 /* find the index of the sample that includes the data for @media_time using a
1003 * binary search. Only to be called in optimized cases of linear search below.
1005 * Returns the index of the sample.
1008 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
1011 QtDemuxSample *result;
1014 /* convert media_time to mov format */
1016 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1018 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
1019 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
1020 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
1022 if (G_LIKELY (result))
1023 index = result - str->samples;
1032 /* find the index of the sample that includes the data for @media_offset using a
1035 * Returns the index of the sample.
1038 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
1039 QtDemuxStream * str, gint64 media_offset)
1041 QtDemuxSample *result = str->samples;
1044 if (result == NULL || str->n_samples == 0)
1047 if (media_offset == result->offset)
1051 while (index < str->n_samples - 1) {
1052 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1055 if (media_offset < result->offset)
1066 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1071 /* find the index of the sample that includes the data for @media_time using a
1072 * linear search, and keeping in mind that not all samples may have been parsed
1073 * yet. If possible, it will delegate to binary search.
1075 * Returns the index of the sample.
1078 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
1079 GstClockTime media_time)
1083 QtDemuxSample *sample;
1085 /* convert media_time to mov format */
1087 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1089 sample = str->samples;
1090 if (mov_time == sample->timestamp + sample->pts_offset)
1093 /* use faster search if requested time in already parsed range */
1094 sample = str->samples + str->stbl_index;
1095 if (str->stbl_index >= 0 &&
1096 mov_time <= (sample->timestamp + sample->pts_offset))
1097 return gst_qtdemux_find_index (qtdemux, str, media_time);
1099 while (index < str->n_samples - 1) {
1100 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1103 sample = str->samples + index + 1;
1104 if (mov_time < (sample->timestamp + sample->pts_offset))
1114 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1119 /* find the index of the keyframe needed to decode the sample at @index
1122 * Returns the index of the keyframe.
1125 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1128 guint32 new_index = index;
1130 if (index >= str->n_samples) {
1131 new_index = str->n_samples;
1135 /* all keyframes, return index */
1136 if (str->all_keyframe) {
1141 /* else go back until we have a keyframe */
1143 if (str->samples[new_index].keyframe)
1153 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index before index %u "
1154 "gave %u", index, new_index);
1159 /* find the segment for @time_position for @stream
1161 * Returns the index of the segment containing @time_position.
1162 * Returns the last segment and sets the @eos variable to TRUE
1163 * if the time is beyond the end. @eos may be NULL
1166 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1167 GstClockTime time_position)
1172 GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1173 GST_TIME_ARGS (time_position));
1176 for (i = 0; i < stream->n_segments; i++) {
1177 QtDemuxSegment *segment = &stream->segments[i];
1179 GST_LOG_OBJECT (stream->pad,
1180 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1181 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1183 /* For the last segment we include stop_time in the last segment */
1184 if (i < stream->n_segments - 1) {
1185 if (segment->time <= time_position && time_position < segment->stop_time) {
1186 GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1191 /* Last segment always matches */
1199 /* move the stream @str to the sample position @index.
1201 * Updates @str->sample_index and marks discontinuity if needed.
1204 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1207 /* no change needed */
1208 if (index == str->sample_index)
1211 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1214 /* position changed, we have a discont */
1215 str->sample_index = index;
1216 str->offset_in_sample = 0;
1217 /* Each time we move in the stream we store the position where we are
1219 str->from_sample = index;
1220 str->discont = TRUE;
1224 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1225 gboolean use_sparse, gint64 * key_time, gint64 * key_offset)
1228 gint64 min_byte_offset = -1;
1231 min_offset = desired_time;
1233 /* for each stream, find the index of the sample in the segment
1234 * and move back to the previous keyframe. */
1235 for (n = 0; n < qtdemux->n_streams; n++) {
1237 guint32 index, kindex;
1239 GstClockTime media_start;
1240 GstClockTime media_time;
1241 GstClockTime seg_time;
1242 QtDemuxSegment *seg;
1243 gboolean empty_segment = FALSE;
1245 str = qtdemux->streams[n];
1247 if (str->sparse && !use_sparse)
1250 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1251 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1253 /* get segment and time in the segment */
1254 seg = &str->segments[seg_idx];
1255 seg_time = desired_time - seg->time;
1257 while (QTSEGMENT_IS_EMPTY (seg)) {
1259 empty_segment = TRUE;
1260 GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1263 if (seg_idx == str->n_segments)
1265 seg = &str->segments[seg_idx];
1268 if (seg_idx == str->n_segments) {
1269 /* FIXME track shouldn't have the last segment as empty, but if it
1270 * happens we better handle it */
1274 /* get the media time in the segment */
1275 media_start = seg->media_start + seg_time;
1277 /* get the index of the sample with media time */
1278 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1279 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1280 " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1281 GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1284 if (!empty_segment) {
1285 /* find previous keyframe */
1286 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index);
1288 /* if the keyframe is at a different position, we need to update the
1289 * requested seek time */
1290 if (index != kindex) {
1293 /* get timestamp of keyframe */
1294 media_time = QTSAMPLE_DTS (str, &str->samples[kindex]);
1295 GST_DEBUG_OBJECT (qtdemux,
1296 "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1297 G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1298 str->samples[kindex].offset);
1300 /* keyframes in the segment get a chance to change the
1301 * desired_offset. keyframes out of the segment are
1303 if (media_time >= seg->media_start) {
1304 GstClockTime seg_time;
1306 /* this keyframe is inside the segment, convert back to
1308 seg_time = (media_time - seg->media_start) + seg->time;
1309 if (seg_time < min_offset)
1310 min_offset = seg_time;
1315 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1316 min_byte_offset = str->samples[index].offset;
1320 *key_time = min_offset;
1322 *key_offset = min_byte_offset;
1326 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1327 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1331 g_return_val_if_fail (format != NULL, FALSE);
1332 g_return_val_if_fail (cur != NULL, FALSE);
1333 g_return_val_if_fail (stop != NULL, FALSE);
1335 if (*format == GST_FORMAT_TIME)
1339 if (cur_type != GST_SEEK_TYPE_NONE)
1340 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1341 if (res && stop_type != GST_SEEK_TYPE_NONE)
1342 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1345 *format = GST_FORMAT_TIME;
1350 /* perform seek in push based mode:
1351 find BYTE position to move to based on time and delegate to upstream
1354 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1359 GstSeekType cur_type, stop_type;
1360 gint64 cur, stop, key_cur;
1363 gint64 original_stop;
1366 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1368 gst_event_parse_seek (event, &rate, &format, &flags,
1369 &cur_type, &cur, &stop_type, &stop);
1370 seqnum = gst_event_get_seqnum (event);
1372 /* only forward streaming and seeking is possible */
1374 goto unsupported_seek;
1376 /* convert to TIME if needed and possible */
1377 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1381 /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1382 * the original stop position to use when upstream pushes the new segment
1384 original_stop = stop;
1387 /* find reasonable corresponding BYTE position,
1388 * also try to mind about keyframes, since we can not go back a bit for them
1390 gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, &key_cur, &byte_cur);
1395 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1396 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1399 GST_OBJECT_LOCK (qtdemux);
1400 qtdemux->seek_offset = byte_cur;
1401 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1402 qtdemux->push_seek_start = cur;
1404 qtdemux->push_seek_start = key_cur;
1407 if (stop_type == GST_SEEK_TYPE_NONE) {
1408 qtdemux->push_seek_stop = qtdemux->segment.stop;
1410 qtdemux->push_seek_stop = original_stop;
1412 GST_OBJECT_UNLOCK (qtdemux);
1414 /* BYTE seek event */
1415 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1417 gst_event_set_seqnum (event, seqnum);
1418 res = gst_pad_push_event (qtdemux->sinkpad, event);
1425 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1431 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1436 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1441 /* perform the seek.
1443 * We set all segment_indexes in the streams to unknown and
1444 * adjust the time_position to the desired position. this is enough
1445 * to trigger a segment switch in the streaming thread to start
1446 * streaming from the desired position.
1448 * Keyframe seeking is a little more complicated when dealing with
1449 * segments. Ideally we want to move to the previous keyframe in
1450 * the segment but there might not be a keyframe in the segment. In
1451 * fact, none of the segments could contain a keyframe. We take a
1452 * practical approach: seek to the previous keyframe in the segment,
1453 * if there is none, seek to the beginning of the segment.
1455 * Called with STREAM_LOCK
1458 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1459 guint32 seqnum, GstSeekFlags flags)
1461 gint64 desired_offset;
1464 desired_offset = segment->position;
1466 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1467 GST_TIME_ARGS (desired_offset));
1469 /* may not have enough fragmented info to do this adjustment,
1470 * and we can't scan (and probably should not) at this time with
1471 * possibly flushing upstream */
1472 if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1475 gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, &min_offset, NULL);
1476 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1477 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1478 desired_offset = min_offset;
1481 /* and set all streams to the final position */
1482 gst_flow_combiner_reset (qtdemux->flowcombiner);
1483 for (n = 0; n < qtdemux->n_streams; n++) {
1484 QtDemuxStream *stream = qtdemux->streams[n];
1486 stream->time_position = desired_offset;
1487 stream->accumulated_base = 0;
1488 stream->sample_index = -1;
1489 stream->offset_in_sample = 0;
1490 stream->segment_index = -1;
1491 stream->sent_eos = FALSE;
1492 stream->segment_seqnum = seqnum;
1494 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1495 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1497 segment->position = desired_offset;
1498 segment->time = desired_offset;
1499 if (segment->rate >= 0) {
1500 segment->start = desired_offset;
1502 /* we stop at the end */
1503 if (segment->stop == -1)
1504 segment->stop = segment->duration;
1506 segment->stop = desired_offset;
1509 if (qtdemux->fragmented)
1510 qtdemux->fragmented_seek_pending = TRUE;
1515 /* do a seek in pull based mode */
1517 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1522 GstSeekType cur_type, stop_type;
1526 GstSegment seeksegment;
1528 GstEvent *flush_event;
1531 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1533 gst_event_parse_seek (event, &rate, &format, &flags,
1534 &cur_type, &cur, &stop_type, &stop);
1535 seqnum = gst_event_get_seqnum (event);
1537 /* we have to have a format as the segment format. Try to convert
1539 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1543 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1545 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1549 flush = flags & GST_SEEK_FLAG_FLUSH;
1551 /* stop streaming, either by flushing or by pausing the task */
1553 flush_event = gst_event_new_flush_start ();
1555 gst_event_set_seqnum (flush_event, seqnum);
1556 /* unlock upstream pull_range */
1557 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1558 /* make sure out loop function exits */
1559 gst_qtdemux_push_event (qtdemux, flush_event);
1561 /* non flushing seek, pause the task */
1562 gst_pad_pause_task (qtdemux->sinkpad);
1565 /* wait for streaming to finish */
1566 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1568 /* copy segment, we need this because we still need the old
1569 * segment when we close the current segment. */
1570 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1573 /* configure the segment with the seek variables */
1574 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1575 gst_segment_do_seek (&seeksegment, rate, format, flags,
1576 cur_type, cur, stop_type, stop, &update);
1579 /* now do the seek, this actually never returns FALSE */
1580 gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1582 /* prepare for streaming again */
1584 flush_event = gst_event_new_flush_stop (TRUE);
1586 gst_event_set_seqnum (flush_event, seqnum);
1588 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1589 gst_qtdemux_push_event (qtdemux, flush_event);
1592 /* commit the new segment */
1593 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1595 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1596 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1597 qtdemux->segment.format, qtdemux->segment.position);
1599 gst_message_set_seqnum (msg, seqnum);
1600 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1603 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1604 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1605 qtdemux->sinkpad, NULL);
1607 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1614 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1620 qtdemux_ensure_index (GstQTDemux * qtdemux)
1624 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1626 /* Build complete index */
1627 for (i = 0; i < qtdemux->n_streams; i++) {
1628 QtDemuxStream *stream = qtdemux->streams[i];
1630 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1638 GST_LOG_OBJECT (qtdemux,
1639 "Building complete index of stream %u for seeking failed!", i);
1645 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1648 gboolean res = TRUE;
1649 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1651 switch (GST_EVENT_TYPE (event)) {
1652 case GST_EVENT_SEEK:
1654 #ifndef GST_DISABLE_GST_DEBUG
1655 GstClockTime ts = gst_util_get_timestamp ();
1658 if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1659 /* seek should be handled by upstream, we might need to re-download fragments */
1660 GST_DEBUG_OBJECT (qtdemux,
1661 "let upstream handle seek for fragmented playback");
1665 /* Build complete index for seeking;
1666 * if not a fragmented file at least */
1667 if (!qtdemux->fragmented)
1668 if (!qtdemux_ensure_index (qtdemux))
1670 #ifndef GST_DISABLE_GST_DEBUG
1671 ts = gst_util_get_timestamp () - ts;
1672 GST_INFO_OBJECT (qtdemux,
1673 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1676 if (qtdemux->pullbased) {
1677 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1678 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1679 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1681 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams
1682 && !qtdemux->fragmented) {
1683 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1685 GST_DEBUG_OBJECT (qtdemux,
1686 "ignoring seek in push mode in current state");
1689 gst_event_unref (event);
1692 case GST_EVENT_NAVIGATION:
1694 gst_event_unref (event);
1698 res = gst_pad_event_default (pad, parent, event);
1708 GST_ERROR_OBJECT (qtdemux, "Index failed");
1709 gst_event_unref (event);
1715 /* stream/index return sample that is min/max w.r.t. byte position,
1716 * time is min/max w.r.t. time of samples,
1717 * the latter need not be time of the former sample */
1719 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1720 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1723 gint64 time, min_time;
1724 QtDemuxStream *stream;
1730 for (n = 0; n < qtdemux->n_streams; ++n) {
1733 gboolean set_sample;
1735 str = qtdemux->streams[n];
1742 i = str->n_samples - 1;
1746 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1747 if (str->samples[i].size == 0)
1750 if (fw && (str->samples[i].offset < byte_pos))
1753 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1756 /* move stream to first available sample */
1758 gst_qtdemux_move_stream (qtdemux, str, i);
1762 /* avoid index from sparse streams since they might be far away */
1764 /* determine min/max time */
1765 time = QTSAMPLE_PTS (str, &str->samples[i]);
1766 if (min_time == -1 || (!fw && time > min_time) ||
1767 (fw && time < min_time)) {
1771 /* determine stream with leading sample, to get its position */
1773 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1774 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1782 /* no sample for this stream, mark eos */
1784 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1795 static QtDemuxStream *
1796 _create_stream (void)
1798 QtDemuxStream *stream;
1800 stream = g_new0 (QtDemuxStream, 1);
1801 /* new streams always need a discont */
1802 stream->discont = TRUE;
1803 /* we enable clipping for raw audio/video streams */
1804 stream->need_clip = FALSE;
1805 stream->need_process = FALSE;
1806 stream->segment_index = -1;
1807 stream->time_position = 0;
1808 stream->sample_index = -1;
1809 stream->offset_in_sample = 0;
1810 stream->new_stream = TRUE;
1811 stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1812 stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1813 stream->protected = FALSE;
1814 stream->protection_scheme_type = 0;
1815 stream->protection_scheme_version = 0;
1816 stream->protection_scheme_info = NULL;
1817 g_queue_init (&stream->protection_scheme_event_queue);
1822 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1824 GstStructure *structure;
1825 const gchar *variant;
1826 const GstCaps *mediacaps = NULL;
1828 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1830 structure = gst_caps_get_structure (caps, 0);
1831 variant = gst_structure_get_string (structure, "variant");
1833 if (variant && strcmp (variant, "mss-fragmented") == 0) {
1834 QtDemuxStream *stream;
1835 const GValue *value;
1837 demux->fragmented = TRUE;
1838 demux->mss_mode = TRUE;
1840 if (demux->n_streams > 1) {
1841 /* can't do this, we can only renegotiate for another mss format */
1845 value = gst_structure_get_value (structure, "media-caps");
1848 const GValue *timescale_v;
1850 /* TODO update when stream changes during playback */
1852 if (demux->n_streams == 0) {
1853 stream = _create_stream ();
1854 demux->streams[demux->n_streams] = stream;
1855 demux->n_streams = 1;
1857 stream = demux->streams[0];
1860 timescale_v = gst_structure_get_value (structure, "timescale");
1862 stream->timescale = g_value_get_uint64 (timescale_v);
1864 /* default mss timescale */
1865 stream->timescale = 10000000;
1867 demux->timescale = stream->timescale;
1869 mediacaps = gst_value_get_caps (value);
1870 if (!stream->caps || !gst_caps_is_equal_fixed (mediacaps, stream->caps)) {
1871 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1873 stream->new_caps = TRUE;
1875 gst_caps_replace (&stream->caps, (GstCaps *) mediacaps);
1876 structure = gst_caps_get_structure (mediacaps, 0);
1877 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
1878 stream->subtype = FOURCC_vide;
1880 gst_structure_get_int (structure, "width", &stream->width);
1881 gst_structure_get_int (structure, "height", &stream->height);
1882 gst_structure_get_fraction (structure, "framerate", &stream->fps_n,
1884 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
1886 stream->subtype = FOURCC_soun;
1887 gst_structure_get_int (structure, "channels", &stream->n_channels);
1888 gst_structure_get_int (structure, "rate", &rate);
1889 stream->rate = rate;
1892 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
1894 demux->mss_mode = FALSE;
1901 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
1905 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
1906 gst_pad_stop_task (qtdemux->sinkpad);
1908 if (hard || qtdemux->upstream_format_is_time) {
1909 qtdemux->state = QTDEMUX_STATE_INITIAL;
1910 qtdemux->neededbytes = 16;
1911 qtdemux->todrop = 0;
1912 qtdemux->pullbased = FALSE;
1913 qtdemux->posted_redirect = FALSE;
1914 qtdemux->first_mdat = -1;
1915 qtdemux->header_size = 0;
1916 qtdemux->mdatoffset = -1;
1917 qtdemux->restoredata_offset = -1;
1918 if (qtdemux->mdatbuffer)
1919 gst_buffer_unref (qtdemux->mdatbuffer);
1920 if (qtdemux->restoredata_buffer)
1921 gst_buffer_unref (qtdemux->restoredata_buffer);
1922 qtdemux->mdatbuffer = NULL;
1923 qtdemux->restoredata_buffer = NULL;
1924 qtdemux->mdatleft = 0;
1925 if (qtdemux->comp_brands)
1926 gst_buffer_unref (qtdemux->comp_brands);
1927 qtdemux->comp_brands = NULL;
1928 qtdemux->last_moov_offset = -1;
1929 if (qtdemux->moov_node)
1930 g_node_destroy (qtdemux->moov_node);
1931 qtdemux->moov_node = NULL;
1932 qtdemux->moov_node_compressed = NULL;
1933 if (qtdemux->tag_list)
1934 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
1935 qtdemux->tag_list = NULL;
1937 if (qtdemux->element_index)
1938 gst_object_unref (qtdemux->element_index);
1939 qtdemux->element_index = NULL;
1941 qtdemux->major_brand = 0;
1942 if (qtdemux->pending_newsegment)
1943 gst_event_unref (qtdemux->pending_newsegment);
1944 qtdemux->pending_newsegment = NULL;
1945 qtdemux->upstream_format_is_time = FALSE;
1946 qtdemux->upstream_seekable = FALSE;
1947 qtdemux->upstream_size = 0;
1949 qtdemux->fragment_start = -1;
1950 qtdemux->fragment_start_offset = -1;
1951 qtdemux->duration = 0;
1952 qtdemux->moof_offset = 0;
1953 qtdemux->chapters_track_id = 0;
1954 qtdemux->have_group_id = FALSE;
1955 qtdemux->group_id = G_MAXUINT;
1957 if (qtdemux->protection_system_ids) {
1958 g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
1959 qtdemux->protection_system_ids = NULL;
1961 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
1963 g_queue_clear (&qtdemux->protection_event_queue);
1965 qtdemux->offset = 0;
1966 gst_adapter_clear (qtdemux->adapter);
1967 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
1970 for (n = 0; n < qtdemux->n_streams; n++) {
1971 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
1972 qtdemux->streams[n] = NULL;
1974 qtdemux->n_streams = 0;
1975 qtdemux->n_video_streams = 0;
1976 qtdemux->n_audio_streams = 0;
1977 qtdemux->n_sub_streams = 0;
1978 qtdemux->exposed = FALSE;
1979 qtdemux->fragmented = FALSE;
1980 qtdemux->mss_mode = FALSE;
1981 gst_caps_replace (&qtdemux->media_caps, NULL);
1982 qtdemux->timescale = 0;
1983 qtdemux->got_moov = FALSE;
1984 } else if (qtdemux->mss_mode) {
1985 gst_flow_combiner_reset (qtdemux->flowcombiner);
1986 for (n = 0; n < qtdemux->n_streams; n++)
1987 gst_qtdemux_stream_clear (qtdemux, qtdemux->streams[n]);
1989 gst_flow_combiner_reset (qtdemux->flowcombiner);
1990 for (n = 0; n < qtdemux->n_streams; n++) {
1991 qtdemux->streams[n]->sent_eos = FALSE;
1992 qtdemux->streams[n]->segment_seqnum = 0;
1993 qtdemux->streams[n]->time_position = 0;
1994 qtdemux->streams[n]->accumulated_base = 0;
2000 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2003 GstQTDemux *demux = GST_QTDEMUX (parent);
2004 gboolean res = TRUE;
2006 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2008 switch (GST_EVENT_TYPE (event)) {
2009 case GST_EVENT_SEGMENT:
2012 QtDemuxStream *stream;
2015 GstEvent *segment_event;
2017 /* some debug output */
2018 gst_event_copy_segment (event, &segment);
2019 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2022 if (segment.format == GST_FORMAT_TIME) {
2023 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
2024 gst_event_replace (&demux->pending_newsegment, event);
2025 demux->upstream_format_is_time = TRUE;
2027 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2028 "not in time format");
2030 /* chain will send initial newsegment after pads have been added */
2031 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
2032 GST_DEBUG_OBJECT (demux, "still starting, eating event");
2037 /* check if this matches a time seek we received previously
2038 * FIXME for backwards compatibility reasons we use the
2039 * seek_offset here to compare. In the future we might want to
2040 * change this to use the seqnum as it uniquely should identify
2041 * the segment that corresponds to the seek. */
2042 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2043 ", received segment offset %" G_GINT64_FORMAT,
2044 demux->seek_offset, segment.start);
2045 if (segment.format == GST_FORMAT_BYTES
2046 && demux->seek_offset == segment.start) {
2047 GST_OBJECT_LOCK (demux);
2048 offset = segment.start;
2050 segment.format = GST_FORMAT_TIME;
2051 segment.start = demux->push_seek_start;
2052 segment.stop = demux->push_seek_stop;
2053 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2054 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2055 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2056 GST_OBJECT_UNLOCK (demux);
2059 /* we only expect a BYTE segment, e.g. following a seek */
2060 if (segment.format == GST_FORMAT_BYTES) {
2061 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2062 offset = segment.start;
2064 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2065 NULL, (gint64 *) & segment.start);
2066 if ((gint64) segment.start < 0)
2069 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2070 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2071 NULL, (gint64 *) & segment.stop);
2072 /* keyframe seeking should already arrange for start >= stop,
2073 * but make sure in other rare cases */
2074 segment.stop = MAX (segment.stop, segment.start);
2076 } else if (segment.format == GST_FORMAT_TIME) {
2077 /* push all data on the adapter before starting this
2079 gst_qtdemux_process_adapter (demux, TRUE);
2081 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2085 /* accept upstream's notion of segment and distribute along */
2086 segment.format = GST_FORMAT_TIME;
2087 segment.position = segment.time = segment.start;
2088 segment.duration = demux->segment.duration;
2089 segment.base = gst_segment_to_running_time (&demux->segment,
2090 GST_FORMAT_TIME, demux->segment.position);
2092 gst_segment_copy_into (&segment, &demux->segment);
2093 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2094 segment_event = gst_event_new_segment (&segment);
2095 gst_event_set_seqnum (segment_event, gst_event_get_seqnum (event));
2096 gst_qtdemux_push_event (demux, segment_event);
2098 /* clear leftover in current segment, if any */
2099 gst_adapter_clear (demux->adapter);
2101 /* set up streaming thread */
2102 demux->offset = offset;
2103 if (demux->upstream_format_is_time) {
2104 GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2105 "set values to restart reading from a new atom");
2106 demux->neededbytes = 16;
2109 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2112 demux->todrop = stream->samples[idx].offset - offset;
2113 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2115 /* set up for EOS */
2116 demux->neededbytes = -1;
2121 gst_event_unref (event);
2125 case GST_EVENT_FLUSH_STOP:
2129 dur = demux->segment.duration;
2130 gst_qtdemux_reset (demux, FALSE);
2131 demux->segment.duration = dur;
2135 /* If we are in push mode, and get an EOS before we've seen any streams,
2136 * then error out - we have nowhere to send the EOS */
2137 if (!demux->pullbased) {
2139 gboolean has_valid_stream = FALSE;
2140 for (i = 0; i < demux->n_streams; i++) {
2141 if (demux->streams[i]->pad != NULL) {
2142 has_valid_stream = TRUE;
2146 if (!has_valid_stream)
2147 gst_qtdemux_post_no_playable_stream_error (demux);
2149 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2150 (guint) gst_adapter_available (demux->adapter));
2151 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2157 case GST_EVENT_CAPS:{
2158 GstCaps *caps = NULL;
2160 gst_event_parse_caps (event, &caps);
2161 gst_qtdemux_setcaps (demux, caps);
2163 gst_event_unref (event);
2166 case GST_EVENT_PROTECTION:
2168 const gchar *system_id = NULL;
2170 gst_event_parse_protection (event, &system_id, NULL, NULL);
2171 GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2173 gst_qtdemux_append_protection_system_id (demux, system_id);
2174 /* save the event for later, for source pads that have not been created */
2175 g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2176 /* send it to all pads that already exist */
2177 gst_qtdemux_push_event (demux, event);
2185 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2193 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2195 GstQTDemux *demux = GST_QTDEMUX (element);
2197 GST_OBJECT_LOCK (demux);
2198 if (demux->element_index)
2199 gst_object_unref (demux->element_index);
2201 demux->element_index = gst_object_ref (index);
2203 demux->element_index = NULL;
2205 GST_OBJECT_UNLOCK (demux);
2206 /* object lock might be taken again */
2208 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2209 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2210 demux->element_index, demux->index_id);
2214 gst_qtdemux_get_index (GstElement * element)
2216 GstIndex *result = NULL;
2217 GstQTDemux *demux = GST_QTDEMUX (element);
2219 GST_OBJECT_LOCK (demux);
2220 if (demux->element_index)
2221 result = gst_object_ref (demux->element_index);
2222 GST_OBJECT_UNLOCK (demux);
2224 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2231 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2233 g_free ((gpointer) stream->stco.data);
2234 stream->stco.data = NULL;
2235 g_free ((gpointer) stream->stsz.data);
2236 stream->stsz.data = NULL;
2237 g_free ((gpointer) stream->stsc.data);
2238 stream->stsc.data = NULL;
2239 g_free ((gpointer) stream->stts.data);
2240 stream->stts.data = NULL;
2241 g_free ((gpointer) stream->stss.data);
2242 stream->stss.data = NULL;
2243 g_free ((gpointer) stream->stps.data);
2244 stream->stps.data = NULL;
2245 g_free ((gpointer) stream->ctts.data);
2246 stream->ctts.data = NULL;
2250 gst_qtdemux_stream_flush_segments_data (GstQTDemux * qtdemux,
2251 QtDemuxStream * stream)
2253 g_free (stream->segments);
2254 stream->segments = NULL;
2255 stream->segment_index = -1;
2256 stream->accumulated_base = 0;
2260 gst_qtdemux_stream_flush_samples_data (GstQTDemux * qtdemux,
2261 QtDemuxStream * stream)
2263 g_free (stream->samples);
2264 stream->samples = NULL;
2265 gst_qtdemux_stbl_free (stream);
2268 g_free (stream->ra_entries);
2269 stream->ra_entries = NULL;
2270 stream->n_ra_entries = 0;
2272 stream->sample_index = -1;
2273 stream->stbl_index = -1;
2274 stream->n_samples = 0;
2275 stream->time_position = 0;
2279 gst_qtdemux_stream_clear (GstQTDemux * qtdemux, QtDemuxStream * stream)
2281 if (stream->allocator)
2282 gst_object_unref (stream->allocator);
2283 while (stream->buffers) {
2284 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2285 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2287 if (stream->rgb8_palette) {
2288 gst_memory_unref (stream->rgb8_palette);
2289 stream->rgb8_palette = NULL;
2292 if (stream->pending_tags)
2293 gst_tag_list_unref (stream->pending_tags);
2294 stream->pending_tags = NULL;
2295 g_free (stream->redirect_uri);
2296 stream->redirect_uri = NULL;
2297 stream->sent_eos = FALSE;
2298 stream->sparse = FALSE;
2299 stream->protected = FALSE;
2300 if (stream->protection_scheme_info) {
2301 if (stream->protection_scheme_type == FOURCC_cenc) {
2302 QtDemuxCencSampleSetInfo *info =
2303 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2304 if (info->default_properties)
2305 gst_structure_free (info->default_properties);
2306 if (info->crypto_info)
2307 g_ptr_array_free (info->crypto_info, TRUE);
2309 g_free (stream->protection_scheme_info);
2310 stream->protection_scheme_info = NULL;
2312 stream->protection_scheme_type = 0;
2313 stream->protection_scheme_version = 0;
2314 g_queue_foreach (&stream->protection_scheme_event_queue,
2315 (GFunc) gst_event_unref, NULL);
2316 g_queue_clear (&stream->protection_scheme_event_queue);
2317 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
2318 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
2322 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
2324 gst_qtdemux_stream_clear (qtdemux, stream);
2326 gst_caps_unref (stream->caps);
2327 stream->caps = NULL;
2329 gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
2330 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, stream->pad);
2336 gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int i)
2338 g_assert (i >= 0 && i < qtdemux->n_streams && qtdemux->streams[i] != NULL);
2340 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[i]);
2341 qtdemux->streams[i] = qtdemux->streams[qtdemux->n_streams - 1];
2342 qtdemux->streams[qtdemux->n_streams - 1] = NULL;
2343 qtdemux->n_streams--;
2346 static GstStateChangeReturn
2347 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2349 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2350 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2352 switch (transition) {
2353 case GST_STATE_CHANGE_PAUSED_TO_READY:
2359 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2361 switch (transition) {
2362 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2363 gst_qtdemux_reset (qtdemux, TRUE);
2374 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2376 /* counts as header data */
2377 qtdemux->header_size += length;
2379 /* only consider at least a sufficiently complete ftyp atom */
2383 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2384 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2385 GST_FOURCC_ARGS (qtdemux->major_brand));
2386 if (qtdemux->comp_brands)
2387 gst_buffer_unref (qtdemux->comp_brands);
2388 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2389 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2394 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist,
2395 GstTagList * xmptaglist)
2397 /* Strip out bogus fields */
2399 if (gst_tag_list_get_scope (taglist) == GST_TAG_SCOPE_GLOBAL) {
2400 gst_tag_list_remove_tag (xmptaglist, GST_TAG_VIDEO_CODEC);
2401 gst_tag_list_remove_tag (xmptaglist, GST_TAG_AUDIO_CODEC);
2403 gst_tag_list_remove_tag (xmptaglist, GST_TAG_CONTAINER_FORMAT);
2406 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, xmptaglist);
2408 /* prioritize native tags using _KEEP mode */
2409 gst_tag_list_insert (taglist, xmptaglist, GST_TAG_MERGE_KEEP);
2410 gst_tag_list_unref (xmptaglist);
2415 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2417 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2418 0x97, 0xA9, 0x42, 0xE8,
2419 0x9C, 0x71, 0x99, 0x94,
2420 0x91, 0xE3, 0xAF, 0xAC
2422 static const guint8 playready_uuid[] = {
2423 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2424 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2428 /* counts as header data */
2429 qtdemux->header_size += length;
2431 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2433 if (length <= offset + 16) {
2434 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2438 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2440 GstTagList *taglist;
2442 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2443 length - offset - 16, NULL);
2444 taglist = gst_tag_list_from_xmp_buffer (buf);
2445 gst_buffer_unref (buf);
2447 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
2449 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
2451 const gunichar2 *s_utf16;
2454 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
2455 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
2456 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
2457 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
2461 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
2462 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
2465 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
2466 GST_READ_UINT32_LE (buffer + offset),
2467 GST_READ_UINT32_LE (buffer + offset + 4),
2468 GST_READ_UINT32_LE (buffer + offset + 8),
2469 GST_READ_UINT32_LE (buffer + offset + 12));
2474 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2476 GstSidxParser sidx_parser;
2477 GstIsoffParserResult res;
2480 gst_isoff_qt_sidx_parser_init (&sidx_parser);
2483 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
2485 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
2486 if (res == GST_ISOFF_QT_PARSER_DONE) {
2487 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
2489 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
2492 /* caller verifies at least 8 bytes in buf */
2494 extract_initial_length_and_fourcc (const guint8 * data, guint size,
2495 guint64 * plength, guint32 * pfourcc)
2500 length = QT_UINT32 (data);
2501 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2502 fourcc = QT_FOURCC (data + 4);
2503 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
2506 length = G_MAXUINT64;
2507 } else if (length == 1 && size >= 16) {
2508 /* this means we have an extended size, which is the 64 bit value of
2509 * the next 8 bytes */
2510 length = QT_UINT64 (data + 8);
2511 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2521 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
2523 guint32 version = 0;
2524 GstClockTime duration = 0;
2526 if (!gst_byte_reader_get_uint32_be (br, &version))
2531 if (!gst_byte_reader_get_uint64_be (br, &duration))
2536 if (!gst_byte_reader_get_uint32_be (br, &dur))
2541 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
2542 qtdemux->duration = duration;
2548 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
2554 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
2555 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
2557 if (!stream->parsed_trex && qtdemux->moov_node) {
2559 GstByteReader trex_data;
2561 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
2563 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
2566 guint32 id = 0, dur = 0, size = 0, flags = 0, dummy = 0;
2568 /* skip version/flags */
2569 if (!gst_byte_reader_skip (&trex_data, 4))
2571 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
2573 if (id != stream->track_id)
2575 /* sample description index; ignore */
2576 if (!gst_byte_reader_get_uint32_be (&trex_data, &dummy))
2578 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2580 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
2582 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
2585 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
2586 "duration %d, size %d, flags 0x%x", stream->track_id,
2589 stream->parsed_trex = TRUE;
2590 stream->def_sample_duration = dur;
2591 stream->def_sample_size = size;
2592 stream->def_sample_flags = flags;
2595 /* iterate all siblings */
2596 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
2602 *ds_duration = stream->def_sample_duration;
2603 *ds_size = stream->def_sample_size;
2604 *ds_flags = stream->def_sample_flags;
2606 /* even then, above values are better than random ... */
2607 if (G_UNLIKELY (!stream->parsed_trex)) {
2608 GST_WARNING_OBJECT (qtdemux,
2609 "failed to find fragment defaults for stream %d", stream->track_id);
2616 /* This method should be called whenever a more accurate duration might
2617 * have been found. It will update all relevant variables if/where needed
2620 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
2624 GstClockTime prevdur;
2626 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
2628 if (movdur > qtdemux->duration) {
2629 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
2630 GST_DEBUG_OBJECT (qtdemux,
2631 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
2632 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
2633 qtdemux->duration = movdur;
2634 GST_DEBUG_OBJECT (qtdemux,
2635 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
2636 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
2637 GST_TIME_ARGS (qtdemux->segment.stop));
2638 if (qtdemux->segment.duration == prevdur) {
2639 /* If the current segment has duration/stop identical to previous duration
2640 * update them also (because they were set at that point in time with
2641 * the wrong duration */
2642 /* We convert the value *from* the timescale version to avoid rounding errors */
2643 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
2644 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
2645 qtdemux->segment.duration = fixeddur;
2646 qtdemux->segment.stop = fixeddur;
2649 for (i = 0; i < qtdemux->n_streams; i++) {
2650 QtDemuxStream *stream = qtdemux->streams[i];
2652 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
2653 if (movdur > stream->duration) {
2654 GST_DEBUG_OBJECT (qtdemux,
2655 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
2656 GST_TIME_ARGS (duration));
2657 stream->duration = movdur;
2658 if (stream->dummy_segment) {
2659 /* Update all dummy values to new duration */
2660 stream->segments[0].stop_time = duration;
2661 stream->segments[0].duration = duration;
2662 stream->segments[0].media_stop = duration;
2670 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
2671 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
2672 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
2673 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts)
2675 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
2677 gint32 data_offset = 0;
2678 guint32 flags = 0, first_flags = 0, samples_count = 0;
2681 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
2682 QtDemuxSample *sample;
2683 gboolean ismv = FALSE;
2685 GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
2686 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
2687 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
2688 d_sample_size, d_sample_flags, *base_offset, decode_ts);
2690 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
2691 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
2695 /* presence of stss or not can't really tell us much,
2696 * and flags and so on tend to be marginally reliable in these files */
2697 if (stream->subtype == FOURCC_soun) {
2698 GST_DEBUG_OBJECT (qtdemux,
2699 "sound track in fragmented file; marking all keyframes");
2700 stream->all_keyframe = TRUE;
2703 if (!gst_byte_reader_skip (trun, 1) ||
2704 !gst_byte_reader_get_uint24_be (trun, &flags))
2707 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
2710 if (flags & TR_DATA_OFFSET) {
2711 /* note this is really signed */
2712 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
2714 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
2715 /* default base offset = first byte of moof */
2716 if (*base_offset == -1) {
2717 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
2718 *base_offset = moof_offset;
2720 *running_offset = *base_offset + data_offset;
2722 /* if no offset at all, that would mean data starts at moof start,
2723 * which is a bit wrong and is ismv crappy way, so compensate
2724 * assuming data is in mdat following moof */
2725 if (*base_offset == -1) {
2726 *base_offset = moof_offset + moof_length + 8;
2727 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
2730 if (*running_offset == -1)
2731 *running_offset = *base_offset;
2734 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
2736 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
2737 data_offset, flags, samples_count);
2739 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2740 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
2741 GST_DEBUG_OBJECT (qtdemux,
2742 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
2743 flags ^= TR_FIRST_SAMPLE_FLAGS;
2745 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
2747 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
2751 /* FIXME ? spec says other bits should also be checked to determine
2752 * entry size (and prefix size for that matter) */
2754 dur_offset = size_offset = 0;
2755 if (flags & TR_SAMPLE_DURATION) {
2756 GST_LOG_OBJECT (qtdemux, "entry duration present");
2757 dur_offset = entry_size;
2760 if (flags & TR_SAMPLE_SIZE) {
2761 GST_LOG_OBJECT (qtdemux, "entry size present");
2762 size_offset = entry_size;
2765 if (flags & TR_SAMPLE_FLAGS) {
2766 GST_LOG_OBJECT (qtdemux, "entry flags present");
2767 flags_offset = entry_size;
2770 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2771 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
2772 ct_offset = entry_size;
2776 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
2778 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
2780 if (stream->n_samples + samples_count >=
2781 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
2784 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
2785 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
2786 (stream->n_samples + samples_count) *
2787 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
2789 /* create a new array of samples if it's the first sample parsed */
2790 if (stream->n_samples == 0) {
2791 g_assert (stream->samples == NULL);
2792 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
2793 /* or try to reallocate it with space enough to insert the new samples */
2795 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
2796 stream->n_samples + samples_count);
2797 if (stream->samples == NULL)
2800 if (qtdemux->fragment_start != -1) {
2801 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
2802 qtdemux->fragment_start = -1;
2804 if (stream->n_samples == 0) {
2805 if (decode_ts > 0) {
2806 timestamp = decode_ts;
2807 } else if (stream->pending_seek != NULL) {
2808 /* if we don't have a timestamp from a tfdt box, we'll use the one
2809 * from the mfra seek table */
2810 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
2811 GST_TIME_ARGS (stream->pending_seek->ts));
2813 /* FIXME: this is not fully correct, the timestamp refers to the random
2814 * access sample refered to in the tfra entry, which may not necessarily
2815 * be the first sample in the tfrag/trun (but hopefully/usually is) */
2816 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
2821 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
2822 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
2823 GST_TIME_ARGS (gst_ts));
2825 /* subsequent fragments extend stream */
2827 stream->samples[stream->n_samples - 1].timestamp +
2828 stream->samples[stream->n_samples - 1].duration;
2830 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
2831 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
2832 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
2836 sample = stream->samples + stream->n_samples;
2837 for (i = 0; i < samples_count; i++) {
2838 guint32 dur, size, sflags, ct;
2840 /* first read sample data */
2841 if (flags & TR_SAMPLE_DURATION) {
2842 dur = QT_UINT32 (data + dur_offset);
2844 dur = d_sample_duration;
2846 if (flags & TR_SAMPLE_SIZE) {
2847 size = QT_UINT32 (data + size_offset);
2849 size = d_sample_size;
2851 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2853 sflags = first_flags;
2855 sflags = d_sample_flags;
2857 } else if (flags & TR_SAMPLE_FLAGS) {
2858 sflags = QT_UINT32 (data + flags_offset);
2860 sflags = d_sample_flags;
2862 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2863 ct = QT_UINT32 (data + ct_offset);
2869 /* fill the sample information */
2870 sample->offset = *running_offset;
2871 sample->pts_offset = ct;
2872 sample->size = size;
2873 sample->timestamp = timestamp;
2874 sample->duration = dur;
2875 /* sample-is-difference-sample */
2876 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
2877 * now idea how it relates to bitfield other than massive LE/BE confusion */
2878 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
2879 *running_offset += size;
2884 /* Update total duration if needed */
2885 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
2887 stream->n_samples += samples_count;
2889 if (stream->pending_seek != NULL)
2890 stream->pending_seek = NULL;
2896 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
2901 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
2907 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
2908 "be larger than %uMB (broken file?)", stream->n_samples,
2909 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
2914 /* find stream with @id */
2915 static inline QtDemuxStream *
2916 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
2918 QtDemuxStream *stream;
2922 if (G_UNLIKELY (!id)) {
2923 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
2927 /* try to get it fast and simple */
2928 if (G_LIKELY (id <= qtdemux->n_streams)) {
2929 stream = qtdemux->streams[id - 1];
2930 if (G_LIKELY (stream->track_id == id))
2934 /* linear search otherwise */
2935 for (i = 0; i < qtdemux->n_streams; i++) {
2936 stream = qtdemux->streams[i];
2937 if (stream->track_id == id)
2940 if (qtdemux->mss_mode) {
2941 /* mss should have only 1 stream anyway */
2942 return qtdemux->streams[0];
2949 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
2950 guint32 * fragment_number)
2952 if (!gst_byte_reader_skip (mfhd, 4))
2954 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
2959 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
2965 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
2966 QtDemuxStream ** stream, guint32 * default_sample_duration,
2967 guint32 * default_sample_size, guint32 * default_sample_flags,
2968 gint64 * base_offset)
2971 guint32 track_id = 0;
2973 if (!gst_byte_reader_skip (tfhd, 1) ||
2974 !gst_byte_reader_get_uint24_be (tfhd, &flags))
2977 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
2980 *stream = qtdemux_find_stream (qtdemux, track_id);
2981 if (G_UNLIKELY (!*stream))
2982 goto unknown_stream;
2984 if (flags & TF_DEFAULT_BASE_IS_MOOF)
2985 *base_offset = qtdemux->moof_offset;
2987 if (flags & TF_BASE_DATA_OFFSET)
2988 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
2991 /* obtain stream defaults */
2992 qtdemux_parse_trex (qtdemux, *stream,
2993 default_sample_duration, default_sample_size, default_sample_flags);
2995 /* FIXME: Handle TF_SAMPLE_DESCRIPTION_INDEX properly */
2996 if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
2997 if (!gst_byte_reader_skip (tfhd, 4))
3000 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3001 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3004 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3005 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3008 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3009 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3016 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3021 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
3027 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3028 guint64 * decode_time)
3030 guint32 version = 0;
3032 if (!gst_byte_reader_get_uint32_be (br, &version))
3037 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3040 guint32 dec_time = 0;
3041 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3043 *decode_time = dec_time;
3046 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3053 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3058 /* Returns a pointer to a GstStructure containing the properties of
3059 * the stream sample identified by @sample_index. The caller must unref
3060 * the returned object after use. Returns NULL if unsuccessful. */
3061 static GstStructure *
3062 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3063 QtDemuxStream * stream, guint sample_index)
3065 QtDemuxCencSampleSetInfo *info = NULL;
3067 g_return_val_if_fail (stream != NULL, NULL);
3068 g_return_val_if_fail (stream->protected, NULL);
3069 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3071 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3073 /* Currently, cenc properties for groups of samples are not supported, so
3074 * simply return a copy of the default sample properties */
3075 return gst_structure_copy (info->default_properties);
3078 /* Parses the sizes of sample auxiliary information contained within a stream,
3079 * as given in a saiz box. Returns array of sample_count guint8 size values,
3080 * or NULL on failure */
3082 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3083 GstByteReader * br, guint32 * sample_count)
3087 guint8 default_info_size;
3089 g_return_val_if_fail (qtdemux != NULL, NULL);
3090 g_return_val_if_fail (stream != NULL, NULL);
3091 g_return_val_if_fail (br != NULL, NULL);
3092 g_return_val_if_fail (sample_count != NULL, NULL);
3094 if (!gst_byte_reader_get_uint32_be (br, &flags))
3098 /* aux_info_type and aux_info_type_parameter are ignored */
3099 if (!gst_byte_reader_skip (br, 8))
3103 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3105 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3107 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3109 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3112 if (default_info_size == 0) {
3113 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3117 info_sizes = g_new (guint8, *sample_count);
3118 memset (info_sizes, default_info_size, *sample_count);
3124 /* Parses the offset of sample auxiliary information contained within a stream,
3125 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3127 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3128 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3133 guint32 aux_info_type = 0;
3134 guint32 aux_info_type_parameter = 0;
3135 guint32 entry_count;
3139 g_return_val_if_fail (qtdemux != NULL, FALSE);
3140 g_return_val_if_fail (stream != NULL, FALSE);
3141 g_return_val_if_fail (br != NULL, FALSE);
3142 g_return_val_if_fail (offset != NULL, FALSE);
3144 if (!gst_byte_reader_get_uint8 (br, &version))
3147 if (!gst_byte_reader_get_uint24_be (br, &flags))
3151 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type))
3153 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3155 } else if (stream->protected) {
3156 aux_info_type = stream->protection_scheme_type;
3158 aux_info_type = stream->fourcc;
3162 *info_type = aux_info_type;
3163 if (info_type_parameter)
3164 *info_type_parameter = aux_info_type_parameter;
3166 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3167 "aux_info_type_parameter: %#06x",
3168 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3170 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3173 if (entry_count != 1) {
3174 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3179 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3181 *offset = (guint64) off_32;
3183 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3188 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3193 qtdemux_gst_structure_free (GstStructure * gststructure)
3196 gst_structure_free (gststructure);
3200 /* Parses auxiliary information relating to samples protected using Common
3201 * Encryption (cenc); the format of this information is defined in
3202 * ISO/IEC 23001-7. Returns TRUE if successful; FALSE otherwise. */
3204 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3205 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3207 QtDemuxCencSampleSetInfo *ss_info = NULL;
3211 g_return_val_if_fail (qtdemux != NULL, FALSE);
3212 g_return_val_if_fail (stream != NULL, FALSE);
3213 g_return_val_if_fail (br != NULL, FALSE);
3214 g_return_val_if_fail (stream->protected, FALSE);
3215 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3217 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3219 if (ss_info->crypto_info) {
3220 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
3221 g_ptr_array_free (ss_info->crypto_info, TRUE);
3224 ss_info->crypto_info =
3225 g_ptr_array_new_full (sample_count,
3226 (GDestroyNotify) qtdemux_gst_structure_free);
3228 for (i = 0; i < sample_count; ++i) {
3229 GstStructure *properties;
3230 guint16 n_subsamples;
3235 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3236 if (properties == NULL) {
3237 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3240 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3241 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3242 gst_structure_free (properties);
3245 if (!gst_byte_reader_dup_data (br, iv_size, &data)) {
3246 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3247 gst_structure_free (properties);
3250 buf = gst_buffer_new_wrapped (data, iv_size);
3251 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3252 size = info_sizes[i];
3253 if (size > iv_size) {
3254 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3255 || !(n_subsamples > 0)) {
3256 gst_structure_free (properties);
3257 GST_ERROR_OBJECT (qtdemux,
3258 "failed to get subsample count for sample %u", i);
3261 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3262 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3263 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3265 gst_structure_free (properties);
3268 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3270 gst_structure_free (properties);
3273 gst_structure_set (properties,
3274 "subsample_count", G_TYPE_UINT, n_subsamples,
3275 "subsamples", GST_TYPE_BUFFER, buf, NULL);
3277 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3279 g_ptr_array_add (ss_info->crypto_info, properties);
3284 /* Converts a UUID in raw byte form to a string representation, as defined in
3285 * RFC 4122. The caller takes ownership of the returned string and is
3286 * responsible for freeing it after use. */
3288 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3290 const guint8 *uuid = (const guint8 *) uuid_bytes;
3292 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3293 "%02x%02x-%02x%02x%02x%02x%02x%02x",
3294 uuid[0], uuid[1], uuid[2], uuid[3],
3295 uuid[4], uuid[5], uuid[6], uuid[7],
3296 uuid[8], uuid[9], uuid[10], uuid[11],
3297 uuid[12], uuid[13], uuid[14], uuid[15]);
3300 /* Parses a Protection System Specific Header box (pssh), as defined in the
3301 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3302 * information needed by a specific content protection system in order to
3303 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3306 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
3308 gchar *sysid_string;
3309 guint32 pssh_size = QT_UINT32 (node->data);
3310 GstBuffer *pssh = NULL;
3311 GstEvent *event = NULL;
3312 guint32 parent_box_type;
3315 if (G_UNLIKELY (pssh_size < 32U)) {
3316 GST_ERROR_OBJECT (qtdemux, "invalid box size");
3321 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
3323 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
3325 pssh = gst_buffer_new_wrapped (g_memdup (node->data, pssh_size), pssh_size);
3326 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
3327 gst_buffer_get_size (pssh));
3329 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
3331 /* Push an event containing the pssh box onto the queues of all streams. */
3332 event = gst_event_new_protection (sysid_string, pssh,
3333 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
3334 for (i = 0; i < qtdemux->n_streams; ++i) {
3335 g_queue_push_tail (&qtdemux->streams[i]->protection_scheme_event_queue,
3336 gst_event_ref (event));
3338 g_free (sysid_string);
3339 gst_event_unref (event);
3340 gst_buffer_unref (pssh);
3345 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
3346 guint64 moof_offset, QtDemuxStream * stream)
3348 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
3349 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
3350 GNode *saiz_node, *saio_node, *pssh_node;
3351 GstByteReader saiz_data, saio_data;
3352 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
3353 gint64 base_offset, running_offset;
3356 /* NOTE @stream ignored */
3358 moof_node = g_node_new ((guint8 *) buffer);
3359 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
3360 qtdemux_node_dump (qtdemux, moof_node);
3362 /* Get fragment number from mfhd and check it's valid */
3364 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
3365 if (mfhd_node == NULL)
3367 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
3369 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
3371 /* unknown base_offset to start with */
3372 base_offset = running_offset = -1;
3373 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
3375 guint64 decode_time = 0;
3377 /* Fragment Header node */
3379 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
3383 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
3384 &ds_size, &ds_flags, &base_offset))
3387 /* The following code assumes at most a single set of sample auxiliary
3388 * data in the fragment (consisting of a saiz box and a corresponding saio
3389 * box); in theory, however, there could be multiple sets of sample
3390 * auxiliary data in a fragment. */
3392 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
3395 guint32 info_type = 0;
3397 guint32 info_type_parameter = 0;
3399 g_free (qtdemux->cenc_aux_info_sizes);
3401 qtdemux->cenc_aux_info_sizes =
3402 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
3403 &qtdemux->cenc_aux_sample_count);
3404 if (qtdemux->cenc_aux_info_sizes == NULL) {
3405 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
3409 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
3412 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
3413 g_free (qtdemux->cenc_aux_info_sizes);
3414 qtdemux->cenc_aux_info_sizes = NULL;
3418 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
3419 &info_type, &info_type_parameter, &offset))) {
3420 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
3421 g_free (qtdemux->cenc_aux_info_sizes);
3422 qtdemux->cenc_aux_info_sizes = NULL;
3425 if (base_offset > qtdemux->moof_offset)
3426 offset += (guint64) (base_offset - qtdemux->moof_offset);
3427 if (info_type == FOURCC_cenc && info_type_parameter == 0U) {
3429 if (offset > length) {
3430 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
3431 qtdemux->cenc_aux_info_offset = offset;
3433 gst_byte_reader_init (&br, buffer + offset, length - offset);
3434 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
3435 qtdemux->cenc_aux_info_sizes,
3436 qtdemux->cenc_aux_sample_count)) {
3437 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
3438 g_free (qtdemux->cenc_aux_info_sizes);
3439 qtdemux->cenc_aux_info_sizes = NULL;
3447 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
3450 GstClockTime decode_time_ts;
3452 /* We'll use decode_time to interpolate timestamps
3453 * in case the input timestamps are missing */
3454 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
3456 decode_time_ts = QTSTREAMTIME_TO_GSTTIME (stream, decode_time);
3458 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
3459 " (%" GST_TIME_FORMAT ")", decode_time,
3460 GST_TIME_ARGS (decode_time_ts));
3462 /* Discard the fragment buffer timestamp info to avoid using it.
3463 * Rely on tfdt instead as it is more accurate than the timestamp
3464 * that is fetched from a manifest/playlist and is usually
3466 qtdemux->fragment_start = -1;
3469 if (G_UNLIKELY (!stream)) {
3470 /* we lost track of offset, we'll need to regain it,
3471 * but can delay complaining until later or avoid doing so altogether */
3475 if (G_UNLIKELY (base_offset < -1))
3478 if (qtdemux->upstream_format_is_time)
3479 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
3481 /* Track Run node */
3483 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
3486 qtdemux_parse_trun (qtdemux, &trun_data, stream,
3487 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
3488 &running_offset, decode_time);
3489 /* iterate all siblings */
3490 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
3493 /* if no new base_offset provided for next traf,
3494 * base is end of current traf */
3495 base_offset = running_offset;
3496 running_offset = -1;
3498 /* iterate all siblings */
3499 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
3502 /* parse any protection system info */
3503 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
3505 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
3506 qtdemux_parse_pssh (qtdemux, pssh_node);
3507 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
3510 g_node_destroy (moof_node);
3515 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
3520 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
3525 GST_DEBUG_OBJECT (qtdemux, "lost offset");
3530 g_node_destroy (moof_node);
3531 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
3532 (_("This file is corrupt and cannot be played.")), (NULL));
3538 /* might be used if some day we actually use mfra & co
3539 * for random access to fragments,
3540 * but that will require quite some modifications and much less relying
3541 * on a sample array */
3545 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
3547 QtDemuxStream *stream;
3548 guint32 ver_flags, track_id, len, num_entries, i;
3549 guint value_size, traf_size, trun_size, sample_size;
3550 guint64 time = 0, moof_offset = 0;
3552 GstBuffer *buf = NULL;
3557 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
3559 if (!gst_byte_reader_skip (&tfra, 8))
3562 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
3565 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
3566 || !gst_byte_reader_get_uint32_be (&tfra, &len)
3567 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
3570 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
3572 stream = qtdemux_find_stream (qtdemux, track_id);
3574 goto unknown_trackid;
3576 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
3577 sample_size = (len & 3) + 1;
3578 trun_size = ((len & 12) >> 2) + 1;
3579 traf_size = ((len & 48) >> 4) + 1;
3581 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
3582 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
3584 if (num_entries == 0)
3587 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
3588 value_size + value_size + traf_size + trun_size + sample_size))
3591 g_free (stream->ra_entries);
3592 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
3593 stream->n_ra_entries = num_entries;
3595 for (i = 0; i < num_entries; i++) {
3596 qt_atom_parser_get_offset (&tfra, value_size, &time);
3597 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
3598 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
3599 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
3600 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
3602 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
3604 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
3605 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
3607 stream->ra_entries[i].ts = time;
3608 stream->ra_entries[i].moof_offset = moof_offset;
3610 /* don't want to go through the entire file and read all moofs at startup */
3612 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
3613 if (ret != GST_FLOW_OK)
3615 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
3616 moof_offset, stream);
3617 gst_buffer_unref (buf);
3621 check_update_duration (qtdemux, time);
3628 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
3633 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
3638 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
3644 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
3646 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
3647 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
3648 GstBuffer *mfro = NULL, *mfra = NULL;
3650 gboolean ret = FALSE;
3651 GNode *mfra_node, *tfra_node;
3652 guint64 mfra_offset = 0;
3653 guint32 fourcc, mfra_size;
3656 /* query upstream size in bytes */
3657 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
3658 goto size_query_failed;
3660 /* mfro box should be at the very end of the file */
3661 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
3662 if (flow != GST_FLOW_OK)
3665 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
3667 fourcc = QT_FOURCC (mfro_map.data + 4);
3668 if (fourcc != FOURCC_mfro)
3671 GST_INFO_OBJECT (qtdemux, "Found mfro box");
3672 if (mfro_map.size < 16)
3673 goto invalid_mfro_size;
3675 mfra_size = QT_UINT32 (mfro_map.data + 12);
3676 if (mfra_size >= len)
3677 goto invalid_mfra_size;
3679 mfra_offset = len - mfra_size;
3681 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
3682 mfra_offset, mfra_size);
3684 /* now get and parse mfra box */
3685 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
3686 if (flow != GST_FLOW_OK)
3689 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
3691 mfra_node = g_node_new ((guint8 *) mfra_map.data);
3692 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
3694 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
3697 qtdemux_parse_tfra (qtdemux, tfra_node);
3698 /* iterate all siblings */
3699 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
3701 g_node_destroy (mfra_node);
3703 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
3709 if (mfro_map.memory != NULL)
3710 gst_buffer_unmap (mfro, &mfro_map);
3711 gst_buffer_unref (mfro);
3714 if (mfra_map.memory != NULL)
3715 gst_buffer_unmap (mfra, &mfra_map);
3716 gst_buffer_unref (mfra);
3723 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
3728 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
3733 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
3738 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
3744 add_offset (guint64 offset, guint64 advance)
3746 /* Avoid 64-bit overflow by clamping */
3747 if (offset > G_MAXUINT64 - advance)
3749 return offset + advance;
3752 static GstFlowReturn
3753 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
3757 GstBuffer *buf = NULL;
3758 GstFlowReturn ret = GST_FLOW_OK;
3759 guint64 cur_offset = qtdemux->offset;
3762 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
3763 if (G_UNLIKELY (ret != GST_FLOW_OK))
3765 gst_buffer_map (buf, &map, GST_MAP_READ);
3766 if (G_LIKELY (map.size >= 8))
3767 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
3768 gst_buffer_unmap (buf, &map);
3769 gst_buffer_unref (buf);
3771 /* maybe we already got most we needed, so only consider this eof */
3772 if (G_UNLIKELY (length == 0)) {
3773 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
3774 (_("Invalid atom size.")),
3775 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
3776 GST_FOURCC_ARGS (fourcc)));
3783 /* record for later parsing when needed */
3784 if (!qtdemux->moof_offset) {
3785 qtdemux->moof_offset = qtdemux->offset;
3787 if (qtdemux_pull_mfro_mfra (qtdemux)) {
3790 qtdemux->offset += length; /* skip moof and keep going */
3792 if (qtdemux->got_moov) {
3793 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
3804 GST_LOG_OBJECT (qtdemux,
3805 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
3806 GST_FOURCC_ARGS (fourcc), cur_offset);
3807 qtdemux->offset = add_offset (qtdemux->offset, length);
3812 GstBuffer *moov = NULL;
3814 if (qtdemux->got_moov) {
3815 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
3816 qtdemux->offset = add_offset (qtdemux->offset, length);
3820 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
3821 if (ret != GST_FLOW_OK)
3823 gst_buffer_map (moov, &map, GST_MAP_READ);
3825 if (length != map.size) {
3826 /* Some files have a 'moov' atom at the end of the file which contains
3827 * a terminal 'free' atom where the body of the atom is missing.
3828 * Check for, and permit, this special case.
3830 if (map.size >= 8) {
3831 guint8 *final_data = map.data + (map.size - 8);
3832 guint32 final_length = QT_UINT32 (final_data);
3833 guint32 final_fourcc = QT_FOURCC (final_data + 4);
3835 if (final_fourcc == FOURCC_free
3836 && map.size + final_length - 8 == length) {
3837 /* Ok, we've found that special case. Allocate a new buffer with
3838 * that free atom actually present. */
3839 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
3840 gst_buffer_fill (newmoov, 0, map.data, map.size);
3841 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
3842 gst_buffer_unmap (moov, &map);
3843 gst_buffer_unref (moov);
3845 gst_buffer_map (moov, &map, GST_MAP_READ);
3850 if (length != map.size) {
3851 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
3852 (_("This file is incomplete and cannot be played.")),
3853 ("We got less than expected (received %" G_GSIZE_FORMAT
3854 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
3855 (guint) length, cur_offset));
3856 gst_buffer_unmap (moov, &map);
3857 gst_buffer_unref (moov);
3858 ret = GST_FLOW_ERROR;
3861 qtdemux->offset += length;
3863 qtdemux_parse_moov (qtdemux, map.data, length);
3864 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
3866 qtdemux_parse_tree (qtdemux);
3867 g_node_destroy (qtdemux->moov_node);
3868 gst_buffer_unmap (moov, &map);
3869 gst_buffer_unref (moov);
3870 qtdemux->moov_node = NULL;
3871 qtdemux->got_moov = TRUE;
3877 GstBuffer *ftyp = NULL;
3879 /* extract major brand; might come in handy for ISO vs QT issues */
3880 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
3881 if (ret != GST_FLOW_OK)
3883 qtdemux->offset += length;
3884 gst_buffer_map (ftyp, &map, GST_MAP_READ);
3885 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
3886 gst_buffer_unmap (ftyp, &map);
3887 gst_buffer_unref (ftyp);
3892 GstBuffer *uuid = NULL;
3894 /* uuid are extension atoms */
3895 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
3896 if (ret != GST_FLOW_OK)
3898 qtdemux->offset += length;
3899 gst_buffer_map (uuid, &map, GST_MAP_READ);
3900 qtdemux_parse_uuid (qtdemux, map.data, map.size);
3901 gst_buffer_unmap (uuid, &map);
3902 gst_buffer_unref (uuid);
3907 GstBuffer *sidx = NULL;
3908 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
3909 if (ret != GST_FLOW_OK)
3911 qtdemux->offset += length;
3912 gst_buffer_map (sidx, &map, GST_MAP_READ);
3913 qtdemux_parse_sidx (qtdemux, map.data, map.size);
3914 gst_buffer_unmap (sidx, &map);
3915 gst_buffer_unref (sidx);
3920 GstBuffer *unknown = NULL;
3922 GST_LOG_OBJECT (qtdemux,
3923 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
3924 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
3926 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
3927 if (ret != GST_FLOW_OK)
3929 gst_buffer_map (unknown, &map, GST_MAP_READ);
3930 GST_MEMDUMP ("Unknown tag", map.data, map.size);
3931 gst_buffer_unmap (unknown, &map);
3932 gst_buffer_unref (unknown);
3933 qtdemux->offset += length;
3939 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
3940 /* digested all data, show what we have */
3941 qtdemux_prepare_streams (qtdemux);
3942 ret = qtdemux_expose_streams (qtdemux);
3944 qtdemux->state = QTDEMUX_STATE_MOVIE;
3945 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
3952 /* Seeks to the previous keyframe of the indexed stream and
3953 * aligns other streams with respect to the keyframe timestamp
3954 * of indexed stream. Only called in case of Reverse Playback
3956 static GstFlowReturn
3957 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
3960 guint32 seg_idx = 0, k_index = 0;
3961 guint32 ref_seg_idx, ref_k_index;
3962 GstClockTime k_pos = 0, last_stop = 0;
3963 QtDemuxSegment *seg = NULL;
3964 QtDemuxStream *ref_str = NULL;
3965 guint64 seg_media_start_mov; /* segment media start time in mov format */
3968 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
3969 * and finally align all the other streams on that timestamp with their
3970 * respective keyframes */
3971 for (n = 0; n < qtdemux->n_streams; n++) {
3972 QtDemuxStream *str = qtdemux->streams[n];
3974 /* No candidate yet, take the first stream */
3980 /* So that stream has a segment, we prefer video streams */
3981 if (str->subtype == FOURCC_vide) {
3987 if (G_UNLIKELY (!ref_str)) {
3988 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
3992 if (G_UNLIKELY (!ref_str->from_sample)) {
3993 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
3997 /* So that stream has been playing from from_sample to to_sample. We will
3998 * get the timestamp of the previous sample and search for a keyframe before
3999 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4000 if (ref_str->subtype == FOURCC_vide) {
4001 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4002 ref_str->from_sample - 1);
4004 if (ref_str->from_sample >= 10)
4005 k_index = ref_str->from_sample - 10;
4011 ref_str->samples[k_index].timestamp +
4012 ref_str->samples[k_index].pts_offset;
4014 /* get current segment for that stream */
4015 seg = &ref_str->segments[ref_str->segment_index];
4016 /* Use segment start in original timescale for comparisons */
4017 seg_media_start_mov = seg->trak_media_start;
4019 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4020 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT "\n",
4021 k_index, target_ts, seg_media_start_mov,
4022 GST_TIME_ARGS (seg->media_start));
4024 /* Crawl back through segments to find the one containing this I frame */
4025 while (target_ts < seg_media_start_mov) {
4026 GST_DEBUG_OBJECT (qtdemux,
4027 "keyframe position (sample %u) is out of segment %u " " target %"
4028 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4029 ref_str->segment_index, target_ts, seg_media_start_mov);
4031 if (G_UNLIKELY (!ref_str->segment_index)) {
4032 /* Reached first segment, let's consider it's EOS */
4035 ref_str->segment_index--;
4036 seg = &ref_str->segments[ref_str->segment_index];
4037 /* Use segment start in original timescale for comparisons */
4038 seg_media_start_mov = seg->trak_media_start;
4040 /* Calculate time position of the keyframe and where we should stop */
4042 QTSTREAMTIME_TO_GSTTIME (ref_str,
4043 target_ts - seg->trak_media_start) + seg->time;
4045 QTSTREAMTIME_TO_GSTTIME (ref_str,
4046 ref_str->samples[ref_str->from_sample].timestamp -
4047 seg->trak_media_start) + seg->time;
4049 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4050 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4051 k_index, GST_TIME_ARGS (k_pos));
4053 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4054 qtdemux->segment.position = last_stop;
4055 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4056 GST_TIME_ARGS (last_stop));
4058 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4059 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4063 ref_seg_idx = ref_str->segment_index;
4064 ref_k_index = k_index;
4066 /* Align them all on this */
4067 for (n = 0; n < qtdemux->n_streams; n++) {
4069 GstClockTime seg_time = 0;
4070 QtDemuxStream *str = qtdemux->streams[n];
4072 /* aligning reference stream again might lead to backing up to yet another
4073 * keyframe (due to timestamp rounding issues),
4074 * potentially putting more load on downstream; so let's try to avoid */
4075 if (str == ref_str) {
4076 seg_idx = ref_seg_idx;
4077 seg = &str->segments[seg_idx];
4078 k_index = ref_k_index;
4079 GST_DEBUG_OBJECT (qtdemux, "reference stream %d segment %d, "
4080 "sample at index %d", n, ref_str->segment_index, k_index);
4082 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4083 GST_DEBUG_OBJECT (qtdemux,
4084 "stream %d align segment %d for keyframe pos %" GST_TIME_FORMAT, n,
4085 seg_idx, GST_TIME_ARGS (k_pos));
4087 /* get segment and time in the segment */
4088 seg = &str->segments[seg_idx];
4089 seg_time = k_pos - seg->time;
4091 /* get the media time in the segment.
4092 * No adjustment for empty "filler" segments */
4093 if (seg->media_start != GST_CLOCK_TIME_NONE)
4094 seg_time += seg->media_start;
4096 /* get the index of the sample with media time */
4097 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4098 GST_DEBUG_OBJECT (qtdemux,
4099 "stream %d sample for %" GST_TIME_FORMAT " at %u", n,
4100 GST_TIME_ARGS (seg_time), index);
4102 /* find previous keyframe */
4103 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index);
4106 /* Remember until where we want to go */
4107 str->to_sample = str->from_sample - 1;
4108 /* Define our time position */
4110 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4111 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4112 if (seg->media_start != GST_CLOCK_TIME_NONE)
4113 str->time_position -= seg->media_start;
4115 /* Now seek back in time */
4116 gst_qtdemux_move_stream (qtdemux, str, k_index);
4117 GST_DEBUG_OBJECT (qtdemux, "stream %d keyframe at %u, time position %"
4118 GST_TIME_FORMAT " playing from sample %u to %u", n, k_index,
4119 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4125 return GST_FLOW_EOS;
4128 /* activate the given segment number @seg_idx of @stream at time @offset.
4129 * @offset is an absolute global position over all the segments.
4131 * This will push out a NEWSEGMENT event with the right values and
4132 * position the stream index to the first decodable sample before
4136 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4137 guint32 seg_idx, GstClockTime offset)
4140 QtDemuxSegment *segment;
4141 guint32 index, kf_index;
4142 GstClockTime seg_time;
4143 GstClockTime start, stop, time;
4146 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
4147 seg_idx, GST_TIME_ARGS (offset));
4149 /* update the current segment */
4150 stream->segment_index = seg_idx;
4152 /* get the segment */
4153 segment = &stream->segments[seg_idx];
4155 if (G_UNLIKELY (offset < segment->time)) {
4156 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4157 GST_TIME_ARGS (segment->time));
4161 /* segment lies beyond total indicated duration */
4162 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4163 segment->time > qtdemux->segment.duration)) {
4164 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4165 " < segment->time %" GST_TIME_FORMAT,
4166 GST_TIME_ARGS (qtdemux->segment.duration),
4167 GST_TIME_ARGS (segment->time));
4171 /* get time in this segment */
4172 seg_time = offset - segment->time;
4174 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4175 GST_TIME_ARGS (seg_time));
4177 if (G_UNLIKELY (seg_time > segment->duration)) {
4178 GST_LOG_OBJECT (stream->pad,
4179 "seg_time > segment->duration %" GST_TIME_FORMAT,
4180 GST_TIME_ARGS (segment->duration));
4181 seg_time = segment->duration;
4184 /* qtdemux->segment.stop is in outside-time-realm, whereas
4185 * segment->media_stop is in track-time-realm.
4187 * In order to compare the two, we need to bring segment.stop
4188 * into the track-time-realm */
4190 stop = qtdemux->segment.stop;
4191 if (stop == GST_CLOCK_TIME_NONE)
4192 stop = qtdemux->segment.duration;
4193 if (stop == GST_CLOCK_TIME_NONE)
4194 stop = segment->media_stop;
4197 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4199 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4200 start = segment->time + seg_time;
4202 stop = start - seg_time + segment->duration;
4203 } else if (qtdemux->segment.rate >= 0) {
4204 start = MIN (segment->media_start + seg_time, stop);
4207 if (segment->media_start >= qtdemux->segment.start) {
4208 time = segment->time;
4210 time = segment->time + (qtdemux->segment.start - segment->media_start);
4213 start = MAX (segment->media_start, qtdemux->segment.start);
4214 stop = MIN (segment->media_start + seg_time, stop);
4217 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
4218 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
4219 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
4221 /* combine global rate with that of the segment */
4222 rate = segment->rate * qtdemux->segment.rate;
4224 /* Copy flags from main segment */
4225 stream->segment.flags = qtdemux->segment.flags;
4227 /* update the segment values used for clipping */
4228 stream->segment.offset = qtdemux->segment.offset;
4229 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
4230 stream->segment.applied_rate = qtdemux->segment.applied_rate;
4231 stream->segment.rate = rate;
4232 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
4233 stream->cslg_shift);
4234 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
4235 stream->cslg_shift);
4236 stream->segment.time = time;
4237 stream->segment.position = stream->segment.start;
4239 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
4242 /* now prepare and send the segment */
4244 event = gst_event_new_segment (&stream->segment);
4245 if (stream->segment_seqnum) {
4246 gst_event_set_seqnum (event, stream->segment_seqnum);
4248 gst_pad_push_event (stream->pad, event);
4249 /* assume we can send more data now */
4250 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
4251 /* clear to send tags on this pad now */
4252 gst_qtdemux_push_tags (qtdemux, stream);
4255 /* in the fragmented case, we pick a fragment that starts before our
4256 * desired position and rely on downstream to wait for a keyframe
4257 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
4258 * tfra entries tells us which trun/sample the key unit is in, but we don't
4259 * make use of this additional information at the moment) */
4260 if (qtdemux->fragmented) {
4261 stream->to_sample = G_MAXUINT32;
4265 /* We don't need to look for a sample in push-based */
4266 if (!qtdemux->pullbased)
4269 /* and move to the keyframe before the indicated media time of the
4271 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
4272 if (qtdemux->segment.rate >= 0) {
4273 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
4274 stream->to_sample = G_MAXUINT32;
4275 GST_DEBUG_OBJECT (stream->pad,
4276 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4277 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
4278 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4280 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
4281 stream->to_sample = index;
4282 GST_DEBUG_OBJECT (stream->pad,
4283 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4284 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
4285 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4288 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
4289 "this is an empty segment");
4293 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
4294 * encountered an error and printed a message so we return appropriately */
4298 /* we're at the right spot */
4299 if (index == stream->sample_index) {
4300 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
4304 /* find keyframe of the target index */
4305 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index);
4308 /* indent does stupid stuff with stream->samples[].timestamp */
4310 /* if we move forwards, we don't have to go back to the previous
4311 * keyframe since we already sent that. We can also just jump to
4312 * the keyframe right before the target index if there is one. */
4313 if (index > stream->sample_index) {
4314 /* moving forwards check if we move past a keyframe */
4315 if (kf_index > stream->sample_index) {
4316 GST_DEBUG_OBJECT (stream->pad,
4317 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4318 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4319 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4320 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4322 GST_DEBUG_OBJECT (stream->pad,
4323 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
4324 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
4325 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
4328 GST_DEBUG_OBJECT (stream->pad,
4329 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4330 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4331 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4332 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4340 /* prepare to get the current sample of @stream, getting essential values.
4342 * This function will also prepare and send the segment when needed.
4344 * Return FALSE if the stream is EOS.
4349 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
4350 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
4351 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
4352 gboolean * keyframe)
4354 QtDemuxSample *sample;
4355 GstClockTime time_position;
4358 g_return_val_if_fail (stream != NULL, FALSE);
4360 time_position = stream->time_position;
4361 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
4364 seg_idx = stream->segment_index;
4365 if (G_UNLIKELY (seg_idx == -1)) {
4366 /* find segment corresponding to time_position if we are looking
4368 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
4371 /* different segment, activate it, sample_index will be set. */
4372 if (G_UNLIKELY (stream->segment_index != seg_idx))
4373 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
4375 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->segments[stream->
4377 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
4379 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
4380 " prepare empty sample");
4383 *pts = *dts = time_position;
4384 *duration = seg->duration - (time_position - seg->time);
4391 if (stream->sample_index == -1)
4392 stream->sample_index = 0;
4394 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
4395 stream->sample_index, stream->n_samples);
4397 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
4398 if (!qtdemux->fragmented)
4401 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
4405 GST_OBJECT_LOCK (qtdemux);
4406 flow = qtdemux_add_fragmented_samples (qtdemux);
4407 GST_OBJECT_UNLOCK (qtdemux);
4409 if (flow != GST_FLOW_OK)
4412 while (stream->sample_index >= stream->n_samples);
4415 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4416 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4417 stream->sample_index);
4421 /* now get the info for the sample we're at */
4422 sample = &stream->samples[stream->sample_index];
4424 *dts = QTSAMPLE_DTS (stream, sample);
4425 *pts = QTSAMPLE_PTS (stream, sample);
4426 *offset = sample->offset;
4427 *size = sample->size;
4428 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
4429 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
4436 stream->time_position = GST_CLOCK_TIME_NONE;
4441 /* move to the next sample in @stream.
4443 * Moves to the next segment when needed.
4446 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
4448 QtDemuxSample *sample;
4449 QtDemuxSegment *segment;
4451 /* get current segment */
4452 segment = &stream->segments[stream->segment_index];
4454 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4455 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
4459 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
4460 /* Mark the stream as EOS */
4461 GST_DEBUG_OBJECT (qtdemux,
4462 "reached max allowed sample %u, mark EOS", stream->to_sample);
4463 stream->time_position = GST_CLOCK_TIME_NONE;
4467 /* move to next sample */
4468 stream->sample_index++;
4469 stream->offset_in_sample = 0;
4471 /* reached the last sample, we need the next segment */
4472 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
4475 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4476 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4477 stream->sample_index);
4481 /* get next sample */
4482 sample = &stream->samples[stream->sample_index];
4484 /* see if we are past the segment */
4485 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
4488 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
4489 /* inside the segment, update time_position, looks very familiar to
4490 * GStreamer segments, doesn't it? */
4491 stream->time_position =
4492 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
4494 /* not yet in segment, time does not yet increment. This means
4495 * that we are still prerolling keyframes to the decoder so it can
4496 * decode the first sample of the segment. */
4497 stream->time_position = segment->time;
4501 /* move to the next segment */
4504 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
4506 if (stream->segment_index == stream->n_segments - 1) {
4507 /* are we at the end of the last segment, we're EOS */
4508 stream->time_position = GST_CLOCK_TIME_NONE;
4510 /* else we're only at the end of the current segment */
4511 stream->time_position = segment->stop_time;
4513 /* make sure we select a new segment */
4515 /* accumulate previous segments */
4516 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
4517 stream->accumulated_base +=
4518 (stream->segment.stop -
4519 stream->segment.start) / ABS (stream->segment.rate);
4521 stream->segment_index = -1;
4526 gst_qtdemux_sync_streams (GstQTDemux * demux)
4530 if (demux->n_streams <= 1)
4533 for (i = 0; i < demux->n_streams; i++) {
4534 QtDemuxStream *stream;
4535 GstClockTime end_time;
4537 stream = demux->streams[i];
4542 /* TODO advance time on subtitle streams here, if any some day */
4544 /* some clips/trailers may have unbalanced streams at the end,
4545 * so send EOS on shorter stream to prevent stalling others */
4547 /* do not mess with EOS if SEGMENT seeking */
4548 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
4551 if (demux->pullbased) {
4552 /* loop mode is sample time based */
4553 if (!STREAM_IS_EOS (stream))
4556 /* push mode is byte position based */
4557 if (stream->n_samples &&
4558 stream->samples[stream->n_samples - 1].offset >= demux->offset)
4562 if (stream->sent_eos)
4565 /* only act if some gap */
4566 end_time = stream->segments[stream->n_segments - 1].stop_time;
4567 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
4568 ", stream end: %" GST_TIME_FORMAT,
4569 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
4570 if (GST_CLOCK_TIME_IS_VALID (end_time)
4571 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
4572 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
4573 GST_PAD_NAME (stream->pad));
4574 stream->sent_eos = TRUE;
4575 gst_pad_push_event (stream->pad, gst_event_new_eos ());
4580 /* EOS and NOT_LINKED need to be combined. This means that we return:
4582 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
4583 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
4585 static GstFlowReturn
4586 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
4589 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
4592 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
4595 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
4597 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
4601 /* the input buffer metadata must be writable. Returns NULL when the buffer is
4602 * completely clipped
4604 * Should be used only with raw buffers */
4606 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
4609 guint64 start, stop, cstart, cstop, diff;
4610 GstClockTime pts, duration;
4612 gint num_rate, denom_rate;
4617 osize = size = gst_buffer_get_size (buf);
4620 /* depending on the type, setup the clip parameters */
4621 if (stream->subtype == FOURCC_soun) {
4622 frame_size = stream->bytes_per_frame;
4623 num_rate = GST_SECOND;
4624 denom_rate = (gint) stream->rate;
4626 } else if (stream->subtype == FOURCC_vide) {
4628 num_rate = stream->fps_n;
4629 denom_rate = stream->fps_d;
4634 if (frame_size <= 0)
4635 goto bad_frame_size;
4637 /* we can only clip if we have a valid pts */
4638 pts = GST_BUFFER_PTS (buf);
4639 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
4642 duration = GST_BUFFER_DURATION (buf);
4644 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
4646 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
4650 stop = start + duration;
4652 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
4653 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
4656 /* see if some clipping happened */
4657 diff = cstart - start;
4663 /* bring clipped time to samples and to bytes */
4664 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
4667 GST_DEBUG_OBJECT (qtdemux,
4668 "clipping start to %" GST_TIME_FORMAT " %"
4669 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
4675 diff = stop - cstop;
4680 /* bring clipped time to samples and then to bytes */
4681 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
4683 GST_DEBUG_OBJECT (qtdemux,
4684 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
4685 " bytes", GST_TIME_ARGS (cstop), diff);
4690 if (offset != 0 || size != osize)
4691 gst_buffer_resize (buf, offset, size);
4693 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
4694 GST_BUFFER_PTS (buf) = pts;
4695 GST_BUFFER_DURATION (buf) = duration;
4699 /* dropped buffer */
4702 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
4707 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
4712 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
4717 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
4718 gst_buffer_unref (buf);
4723 /* the input buffer metadata must be writable,
4724 * but time/duration etc not yet set and need not be preserved */
4726 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
4733 /* not many cases for now */
4734 if (G_UNLIKELY (stream->fourcc == FOURCC_mp4s)) {
4735 /* send a one time dvd clut event */
4736 if (stream->pending_event && stream->pad)
4737 gst_pad_push_event (stream->pad, stream->pending_event);
4738 stream->pending_event = NULL;
4741 if (G_UNLIKELY (stream->subtype != FOURCC_text
4742 && stream->subtype != FOURCC_sbtl &&
4743 stream->subtype != FOURCC_subp)) {
4747 gst_buffer_map (buf, &map, GST_MAP_READ);
4749 /* empty buffer is sent to terminate previous subtitle */
4750 if (map.size <= 2) {
4751 gst_buffer_unmap (buf, &map);
4752 gst_buffer_unref (buf);
4755 if (stream->subtype == FOURCC_subp) {
4756 /* That's all the processing needed for subpictures */
4757 gst_buffer_unmap (buf, &map);
4761 nsize = GST_READ_UINT16_BE (map.data);
4762 nsize = MIN (nsize, map.size - 2);
4764 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
4767 /* takes care of UTF-8 validation or UTF-16 recognition,
4768 * no other encoding expected */
4769 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
4770 gst_buffer_unmap (buf, &map);
4772 gst_buffer_unref (buf);
4773 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
4775 /* this should not really happen unless the subtitle is corrupted */
4776 gst_buffer_unref (buf);
4780 /* FIXME ? convert optional subsequent style info to markup */
4785 /* Sets a buffer's attributes properly and pushes it downstream.
4786 * Also checks for additional actions and custom processing that may
4787 * need to be done first.
4789 static GstFlowReturn
4790 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
4791 QtDemuxStream * stream, GstBuffer * buf,
4792 GstClockTime dts, GstClockTime pts, GstClockTime duration,
4793 gboolean keyframe, GstClockTime position, guint64 byte_position)
4795 GstFlowReturn ret = GST_FLOW_OK;
4797 /* offset the timestamps according to the edit list */
4799 if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) {
4803 gst_buffer_map (buf, &map, GST_MAP_READ);
4804 url = g_strndup ((gchar *) map.data, map.size);
4805 gst_buffer_unmap (buf, &map);
4806 if (url != NULL && strlen (url) != 0) {
4807 /* we have RTSP redirect now */
4808 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
4809 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
4810 gst_structure_new ("redirect",
4811 "new-location", G_TYPE_STRING, url, NULL)));
4812 qtdemux->posted_redirect = TRUE;
4814 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
4820 /* position reporting */
4821 if (qtdemux->segment.rate >= 0) {
4822 qtdemux->segment.position = position;
4823 gst_qtdemux_sync_streams (qtdemux);
4826 if (G_UNLIKELY (!stream->pad)) {
4827 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
4828 gst_buffer_unref (buf);
4832 /* send out pending buffers */
4833 while (stream->buffers) {
4834 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
4836 if (G_UNLIKELY (stream->discont)) {
4837 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
4838 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
4839 stream->discont = FALSE;
4841 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
4844 gst_pad_push (stream->pad, buffer);
4846 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
4849 /* we're going to modify the metadata */
4850 buf = gst_buffer_make_writable (buf);
4852 if (G_UNLIKELY (stream->need_process))
4853 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
4859 GST_BUFFER_DTS (buf) = dts;
4860 GST_BUFFER_PTS (buf) = pts;
4861 GST_BUFFER_DURATION (buf) = duration;
4862 GST_BUFFER_OFFSET (buf) = -1;
4863 GST_BUFFER_OFFSET_END (buf) = -1;
4865 if (G_UNLIKELY (stream->rgb8_palette))
4866 gst_buffer_append_memory (buf, gst_memory_ref (stream->rgb8_palette));
4868 if (G_UNLIKELY (stream->padding)) {
4869 gst_buffer_resize (buf, stream->padding, -1);
4872 if (G_UNLIKELY (qtdemux->element_index)) {
4873 GstClockTime stream_time;
4876 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
4878 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
4879 GST_LOG_OBJECT (qtdemux,
4880 "adding association %" GST_TIME_FORMAT "-> %"
4881 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
4882 gst_index_add_association (qtdemux->element_index,
4884 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
4885 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
4886 GST_FORMAT_BYTES, byte_position, NULL);
4891 if (stream->need_clip)
4892 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
4894 if (G_UNLIKELY (buf == NULL))
4897 if (G_UNLIKELY (stream->discont)) {
4898 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
4899 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
4900 stream->discont = FALSE;
4902 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
4906 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
4907 stream->on_keyframe = FALSE;
4909 stream->on_keyframe = TRUE;
4913 GST_LOG_OBJECT (qtdemux,
4914 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
4915 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
4916 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
4917 GST_PAD_NAME (stream->pad));
4919 if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) {
4920 GstStructure *crypto_info;
4921 QtDemuxCencSampleSetInfo *info =
4922 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
4926 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
4927 gst_pad_push_event (stream->pad, event);
4930 index = stream->sample_index - (stream->n_samples - info->crypto_info->len);
4931 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
4932 /* steal structure from array */
4933 crypto_info = g_ptr_array_index (info->crypto_info, index);
4934 g_ptr_array_index (info->crypto_info, index) = NULL;
4935 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u]", index);
4936 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
4937 GST_ERROR_OBJECT (qtdemux, "failed to attach cenc metadata to buffer");
4941 ret = gst_pad_push (stream->pad, buf);
4943 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
4944 /* mark position in stream, we'll need this to know when to send GAP event */
4945 stream->segment.position = pts + duration;
4952 static const QtDemuxRandomAccessEntry *
4953 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4954 GstClockTime pos, gboolean after)
4956 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
4957 guint n_entries = stream->n_ra_entries;
4960 /* we assume the table is sorted */
4961 for (i = 0; i < n_entries; ++i) {
4962 if (entries[i].ts > pos)
4966 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
4967 * probably okay to assume that the index lists the very first fragment */
4974 return &entries[i - 1];
4978 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
4980 const QtDemuxRandomAccessEntry *best_entry = NULL;
4983 GST_OBJECT_LOCK (qtdemux);
4985 g_assert (qtdemux->n_streams > 0);
4987 for (i = 0; i < qtdemux->n_streams; i++) {
4988 const QtDemuxRandomAccessEntry *entry;
4989 QtDemuxStream *stream;
4990 gboolean is_audio_or_video;
4992 stream = qtdemux->streams[i];
4994 g_free (stream->samples);
4995 stream->samples = NULL;
4996 stream->n_samples = 0;
4997 stream->stbl_index = -1; /* no samples have yet been parsed */
4998 stream->sample_index = -1;
5000 if (stream->ra_entries == NULL)
5003 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
5004 is_audio_or_video = TRUE;
5006 is_audio_or_video = FALSE;
5009 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
5010 stream->time_position, !is_audio_or_video);
5012 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
5013 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
5015 stream->pending_seek = entry;
5017 /* decide position to jump to just based on audio/video tracks, not subs */
5018 if (!is_audio_or_video)
5021 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
5025 if (best_entry == NULL) {
5026 GST_OBJECT_UNLOCK (qtdemux);
5030 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
5031 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
5032 GST_TIME_ARGS (qtdemux->streams[0]->time_position),
5033 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
5035 qtdemux->moof_offset = best_entry->moof_offset;
5037 qtdemux_add_fragmented_samples (qtdemux);
5039 GST_OBJECT_UNLOCK (qtdemux);
5043 static GstFlowReturn
5044 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
5046 GstFlowReturn ret = GST_FLOW_OK;
5047 GstBuffer *buf = NULL;
5048 QtDemuxStream *stream;
5049 GstClockTime min_time;
5051 GstClockTime dts = GST_CLOCK_TIME_NONE;
5052 GstClockTime pts = GST_CLOCK_TIME_NONE;
5053 GstClockTime duration = 0;
5054 gboolean keyframe = FALSE;
5055 guint sample_size = 0;
5061 gst_qtdemux_push_pending_newsegment (qtdemux);
5063 if (qtdemux->fragmented_seek_pending) {
5064 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
5065 gst_qtdemux_do_fragmented_seek (qtdemux);
5066 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
5067 qtdemux->fragmented_seek_pending = FALSE;
5070 /* Figure out the next stream sample to output, min_time is expressed in
5071 * global time and runs over the edit list segments. */
5072 min_time = G_MAXUINT64;
5074 for (i = 0; i < qtdemux->n_streams; i++) {
5075 GstClockTime position;
5077 stream = qtdemux->streams[i];
5078 position = stream->time_position;
5080 /* position of -1 is EOS */
5081 if (position != GST_CLOCK_TIME_NONE && position < min_time) {
5082 min_time = position;
5087 if (G_UNLIKELY (index == -1)) {
5088 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
5092 /* check for segment end */
5093 if (G_UNLIKELY (qtdemux->segment.stop != -1
5094 && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
5095 || (qtdemux->segment.rate < 0
5096 && qtdemux->segment.start > min_time))
5097 && qtdemux->streams[index]->on_keyframe)) {
5098 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
5099 qtdemux->streams[index]->time_position = GST_CLOCK_TIME_NONE;
5103 /* gap events for subtitle streams */
5104 for (i = 0; i < qtdemux->n_streams; i++) {
5105 stream = qtdemux->streams[i];
5106 if (stream->pad && (stream->subtype == FOURCC_subp
5107 || stream->subtype == FOURCC_text
5108 || stream->subtype == FOURCC_sbtl)) {
5109 /* send one second gap events until the stream catches up */
5110 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
5111 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
5112 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
5113 stream->segment.position + GST_SECOND < min_time) {
5115 gst_event_new_gap (stream->segment.position, GST_SECOND);
5116 gst_pad_push_event (stream->pad, gap);
5117 stream->segment.position += GST_SECOND;
5122 stream = qtdemux->streams[index];
5123 if (stream->new_caps) {
5124 gst_qtdemux_configure_stream (qtdemux, stream);
5125 qtdemux_do_allocation (qtdemux, stream);
5128 /* fetch info for the current sample of this stream */
5129 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
5130 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
5133 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
5134 if (G_UNLIKELY (qtdemux->
5135 segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
5136 if (stream->subtype == FOURCC_vide && !keyframe) {
5137 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on stream %d", index);
5142 GST_DEBUG_OBJECT (qtdemux,
5143 "pushing from stream %d, empty %d offset %" G_GUINT64_FORMAT
5144 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
5145 ", duration %" GST_TIME_FORMAT, index, empty, offset, sample_size,
5146 GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
5148 if (G_UNLIKELY (empty)) {
5149 /* empty segment, push a gap and move to the next one */
5150 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
5151 stream->segment.position = pts + duration;
5155 /* hmm, empty sample, skip and move to next sample */
5156 if (G_UNLIKELY (sample_size <= 0))
5159 /* last pushed sample was out of boundary, goto next sample */
5160 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
5163 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
5166 GST_DEBUG_OBJECT (qtdemux,
5167 "size %d larger than stream max_buffer_size %d, trimming",
5168 sample_size, stream->max_buffer_size);
5170 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
5173 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
5176 if (stream->use_allocator) {
5177 /* if we have a per-stream allocator, use it */
5178 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
5181 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
5183 if (G_UNLIKELY (ret != GST_FLOW_OK))
5186 if (size != sample_size) {
5187 pts += gst_util_uint64_scale_int (GST_SECOND,
5188 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
5189 dts += gst_util_uint64_scale_int (GST_SECOND,
5190 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
5191 duration = gst_util_uint64_scale_int (GST_SECOND,
5192 size / stream->bytes_per_frame, stream->timescale);
5195 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
5196 dts, pts, duration, keyframe, min_time, offset);
5198 if (size != sample_size) {
5199 QtDemuxSample *sample = &stream->samples[stream->sample_index];
5200 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
5202 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
5203 sample->timestamp + stream->offset_in_sample / stream->bytes_per_frame);
5204 if (time_position >= segment->media_start) {
5205 /* inside the segment, update time_position, looks very familiar to
5206 * GStreamer segments, doesn't it? */
5207 stream->time_position = (time_position - segment->media_start) +
5210 /* not yet in segment, time does not yet increment. This means
5211 * that we are still prerolling keyframes to the decoder so it can
5212 * decode the first sample of the segment. */
5213 stream->time_position = segment->time;
5218 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
5219 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
5220 * we have no more data for the pad to push */
5221 if (ret == GST_FLOW_EOS)
5224 stream->offset_in_sample += size;
5225 if (stream->offset_in_sample >= sample_size) {
5226 gst_qtdemux_advance_sample (qtdemux, stream);
5231 gst_qtdemux_advance_sample (qtdemux, stream);
5239 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
5245 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
5246 /* EOS will be raised if all are EOS */
5253 gst_qtdemux_loop (GstPad * pad)
5255 GstQTDemux *qtdemux;
5259 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
5261 cur_offset = qtdemux->offset;
5262 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %d",
5263 cur_offset, qtdemux->state);
5265 switch (qtdemux->state) {
5266 case QTDEMUX_STATE_INITIAL:
5267 case QTDEMUX_STATE_HEADER:
5268 ret = gst_qtdemux_loop_state_header (qtdemux);
5270 case QTDEMUX_STATE_MOVIE:
5271 ret = gst_qtdemux_loop_state_movie (qtdemux);
5272 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
5273 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
5281 /* if something went wrong, pause */
5282 if (ret != GST_FLOW_OK)
5286 gst_object_unref (qtdemux);
5292 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
5293 (NULL), ("streaming stopped, invalid state"));
5294 gst_pad_pause_task (pad);
5295 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5300 const gchar *reason = gst_flow_get_name (ret);
5302 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
5304 gst_pad_pause_task (pad);
5306 /* fatal errors need special actions */
5308 if (ret == GST_FLOW_EOS) {
5309 if (qtdemux->n_streams == 0) {
5310 /* we have no streams, post an error */
5311 gst_qtdemux_post_no_playable_stream_error (qtdemux);
5313 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
5316 if ((stop = qtdemux->segment.stop) == -1)
5317 stop = qtdemux->segment.duration;
5319 if (qtdemux->segment.rate >= 0) {
5320 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
5321 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5322 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5323 GST_FORMAT_TIME, stop));
5324 gst_qtdemux_push_event (qtdemux,
5325 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
5327 /* For Reverse Playback */
5328 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
5329 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5330 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5331 GST_FORMAT_TIME, qtdemux->segment.start));
5332 gst_qtdemux_push_event (qtdemux,
5333 gst_event_new_segment_done (GST_FORMAT_TIME,
5334 qtdemux->segment.start));
5337 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
5338 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5340 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
5341 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
5342 (NULL), ("streaming stopped, reason %s", reason));
5343 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5352 * Returns if there are samples to be played.
5355 has_next_entry (GstQTDemux * demux)
5357 QtDemuxStream *stream;
5360 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
5362 for (i = 0; i < demux->n_streams; i++) {
5363 stream = demux->streams[i];
5365 if (stream->sample_index == -1) {
5366 stream->sample_index = 0;
5367 stream->offset_in_sample = 0;
5370 if (stream->sample_index >= stream->n_samples) {
5371 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
5374 GST_DEBUG_OBJECT (demux, "Found a sample");
5378 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
5385 * Returns the size of the first entry at the current offset.
5386 * If -1, there are none (which means EOS or empty file).
5389 next_entry_size (GstQTDemux * demux)
5391 QtDemuxStream *stream;
5394 guint64 smalloffs = (guint64) - 1;
5395 QtDemuxSample *sample;
5397 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
5400 for (i = 0; i < demux->n_streams; i++) {
5401 stream = demux->streams[i];
5403 if (stream->sample_index == -1) {
5404 stream->sample_index = 0;
5405 stream->offset_in_sample = 0;
5408 if (stream->sample_index >= stream->n_samples) {
5409 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
5413 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
5414 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
5415 stream->sample_index);
5419 sample = &stream->samples[stream->sample_index];
5421 GST_LOG_OBJECT (demux,
5422 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
5423 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
5424 sample->offset, sample->size);
5426 if (((smalloffs == -1)
5427 || (sample->offset < smalloffs)) && (sample->size)) {
5429 smalloffs = sample->offset;
5433 GST_LOG_OBJECT (demux,
5434 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
5435 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
5440 stream = demux->streams[smallidx];
5441 sample = &stream->samples[stream->sample_index];
5443 if (sample->offset >= demux->offset) {
5444 demux->todrop = sample->offset - demux->offset;
5445 return sample->size + demux->todrop;
5448 GST_DEBUG_OBJECT (demux,
5449 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
5454 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
5456 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
5458 gst_element_post_message (GST_ELEMENT_CAST (demux),
5459 gst_message_new_element (GST_OBJECT_CAST (demux),
5460 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
5464 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
5469 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
5472 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
5473 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
5474 GST_SEEK_TYPE_NONE, -1);
5476 res = gst_pad_push_event (demux->sinkpad, event);
5481 /* check for seekable upstream, above and beyond a mere query */
5483 gst_qtdemux_check_seekability (GstQTDemux * demux)
5486 gboolean seekable = FALSE;
5487 gint64 start = -1, stop = -1;
5489 if (demux->upstream_size)
5492 query = gst_query_new_seeking (GST_FORMAT_BYTES);
5493 if (!gst_pad_peer_query (demux->sinkpad, query)) {
5494 GST_DEBUG_OBJECT (demux, "seeking query failed");
5498 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
5500 /* try harder to query upstream size if we didn't get it the first time */
5501 if (seekable && stop == -1) {
5502 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
5503 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
5506 /* if upstream doesn't know the size, it's likely that it's not seekable in
5507 * practice even if it technically may be seekable */
5508 if (seekable && (start != 0 || stop <= start)) {
5509 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
5514 gst_query_unref (query);
5516 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
5517 G_GUINT64_FORMAT ")", seekable, start, stop);
5518 demux->upstream_seekable = seekable;
5519 demux->upstream_size = seekable ? stop : -1;
5523 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
5525 g_return_if_fail (bytes <= demux->todrop);
5527 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
5528 gst_adapter_flush (demux->adapter, bytes);
5529 demux->neededbytes -= bytes;
5530 demux->offset += bytes;
5531 demux->todrop -= bytes;
5535 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
5537 if (G_UNLIKELY (demux->pending_newsegment)) {
5540 gst_qtdemux_push_pending_newsegment (demux);
5541 /* clear to send tags on all streams */
5542 for (i = 0; i < demux->n_streams; i++) {
5543 QtDemuxStream *stream;
5544 stream = demux->streams[i];
5545 gst_qtdemux_push_tags (demux, stream);
5546 if (stream->sparse) {
5547 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
5548 gst_pad_push_event (stream->pad,
5549 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
5556 gst_qtdemux_stream_send_initial_gap_segments (GstQTDemux * demux,
5557 QtDemuxStream * stream)
5561 /* Push any initial gap segments before proceeding to the
5563 for (i = 0; i < stream->n_segments; i++) {
5564 gst_qtdemux_activate_segment (demux, stream, i, stream->time_position);
5566 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
5567 GstClockTime ts, dur;
5570 ts = stream->time_position;
5572 stream->segments[i].duration - (stream->time_position -
5573 stream->segments[i].time);
5574 gap = gst_event_new_gap (ts, dur);
5575 stream->time_position += dur;
5577 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
5578 "segment: %" GST_PTR_FORMAT, gap);
5579 gst_pad_push_event (stream->pad, gap);
5581 /* Only support empty segment at the beginning followed by
5582 * one non-empty segment, this was checked when parsing the
5583 * edts atom, arriving here is unexpected */
5584 g_assert (i + 1 == stream->n_segments);
5590 static GstFlowReturn
5591 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
5595 demux = GST_QTDEMUX (parent);
5597 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
5600 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
5602 for (i = 0; i < demux->n_streams; i++) {
5603 demux->streams[i]->discont = TRUE;
5606 /* Reverse fragmented playback, need to flush all we have before
5607 * consuming a new fragment.
5608 * The samples array have the timestamps calculated by accumulating the
5609 * durations but this won't work for reverse playback of fragments as
5610 * the timestamps of a subsequent fragment should be smaller than the
5611 * previously received one. */
5612 if (demux->fragmented && demux->segment.rate < 0) {
5613 gst_qtdemux_process_adapter (demux, TRUE);
5614 for (i = 0; i < demux->n_streams; i++)
5615 gst_qtdemux_stream_flush_samples_data (demux, demux->streams[i]);
5619 gst_adapter_push (demux->adapter, inbuf);
5621 GST_DEBUG_OBJECT (demux,
5622 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
5623 demux->neededbytes, gst_adapter_available (demux->adapter));
5625 return gst_qtdemux_process_adapter (demux, FALSE);
5628 static GstFlowReturn
5629 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
5631 GstFlowReturn ret = GST_FLOW_OK;
5633 /* we never really mean to buffer that much */
5634 if (demux->neededbytes == -1) {
5638 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
5639 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
5641 GST_DEBUG_OBJECT (demux,
5642 "state:%d , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT,
5643 demux->state, demux->neededbytes, demux->offset);
5645 switch (demux->state) {
5646 case QTDEMUX_STATE_INITIAL:{
5651 gst_qtdemux_check_seekability (demux);
5653 data = gst_adapter_map (demux->adapter, demux->neededbytes);
5655 /* get fourcc/length, set neededbytes */
5656 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
5658 gst_adapter_unmap (demux->adapter);
5660 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
5661 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
5663 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
5664 (_("This file is invalid and cannot be played.")),
5665 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
5666 GST_FOURCC_ARGS (fourcc)));
5667 ret = GST_FLOW_ERROR;
5670 if (fourcc == FOURCC_mdat) {
5671 gint next_entry = next_entry_size (demux);
5672 if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
5673 /* we have the headers, start playback */
5674 demux->state = QTDEMUX_STATE_MOVIE;
5675 demux->neededbytes = next_entry;
5676 demux->mdatleft = size;
5678 /* no headers yet, try to get them */
5681 guint64 old, target;
5684 old = demux->offset;
5685 target = old + size;
5687 /* try to jump over the atom with a seek */
5688 /* only bother if it seems worth doing so,
5689 * and avoids possible upstream/server problems */
5690 if (demux->upstream_seekable &&
5691 demux->upstream_size > 4 * (1 << 20)) {
5692 res = qtdemux_seek_offset (demux, target);
5694 GST_DEBUG_OBJECT (demux, "skipping seek");
5699 GST_DEBUG_OBJECT (demux, "seek success");
5700 /* remember the offset fo the first mdat so we can seek back to it
5701 * after we have the headers */
5702 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
5703 demux->first_mdat = old;
5704 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
5707 /* seek worked, continue reading */
5708 demux->offset = target;
5709 demux->neededbytes = 16;
5710 demux->state = QTDEMUX_STATE_INITIAL;
5712 /* seek failed, need to buffer */
5713 demux->offset = old;
5714 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
5715 /* there may be multiple mdat (or alike) buffers */
5717 if (demux->mdatbuffer)
5718 bs = gst_buffer_get_size (demux->mdatbuffer);
5721 if (size + bs > 10 * (1 << 20))
5723 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
5724 demux->neededbytes = size;
5725 if (!demux->mdatbuffer)
5726 demux->mdatoffset = demux->offset;
5729 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
5730 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
5731 (_("This file is invalid and cannot be played.")),
5732 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
5733 GST_FOURCC_ARGS (fourcc), size));
5734 ret = GST_FLOW_ERROR;
5737 /* this means we already started buffering and still no moov header,
5738 * let's continue buffering everything till we get moov */
5739 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
5740 || fourcc == FOURCC_moof))
5742 demux->neededbytes = size;
5743 demux->state = QTDEMUX_STATE_HEADER;
5747 case QTDEMUX_STATE_HEADER:{
5751 GST_DEBUG_OBJECT (demux, "In header");
5753 data = gst_adapter_map (demux->adapter, demux->neededbytes);
5755 /* parse the header */
5756 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
5758 if (fourcc == FOURCC_moov) {
5761 /* in usual fragmented setup we could try to scan for more
5762 * and end up at the the moov (after mdat) again */
5763 if (demux->got_moov && demux->n_streams > 0 &&
5765 || demux->last_moov_offset == demux->offset)) {
5766 GST_DEBUG_OBJECT (demux,
5767 "Skipping moov atom as we have (this) one already");
5769 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
5771 if (demux->got_moov && demux->fragmented) {
5772 GST_DEBUG_OBJECT (demux,
5773 "Got a second moov, clean up data from old one");
5774 if (demux->moov_node)
5775 g_node_destroy (demux->moov_node);
5776 demux->moov_node = NULL;
5777 demux->moov_node_compressed = NULL;
5779 /* prepare newsegment to send when streaming actually starts */
5780 if (!demux->pending_newsegment)
5781 demux->pending_newsegment =
5782 gst_event_new_segment (&demux->segment);
5785 demux->last_moov_offset = demux->offset;
5787 qtdemux_parse_moov (demux, data, demux->neededbytes);
5788 qtdemux_node_dump (demux, demux->moov_node);
5789 qtdemux_parse_tree (demux);
5790 qtdemux_prepare_streams (demux);
5791 if (!demux->got_moov)
5792 qtdemux_expose_streams (demux);
5795 for (n = 0; n < demux->n_streams; n++) {
5796 QtDemuxStream *stream = demux->streams[n];
5798 gst_qtdemux_configure_stream (demux, stream);
5802 demux->got_moov = TRUE;
5803 gst_qtdemux_check_send_pending_segment (demux);
5805 /* fragmented streams headers shouldn't contain edts atoms */
5806 if (!demux->fragmented) {
5807 for (n = 0; n < demux->n_streams; n++) {
5808 gst_qtdemux_stream_send_initial_gap_segments (demux,
5813 g_node_destroy (demux->moov_node);
5814 demux->moov_node = NULL;
5815 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
5817 } else if (fourcc == FOURCC_moof) {
5818 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
5820 GstClockTime prev_pts;
5821 guint64 prev_offset;
5823 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
5826 * The timestamp of the moof buffer is relevant as some scenarios
5827 * won't have the initial timestamp in the atoms. Whenever a new
5828 * buffer has started, we get that buffer's PTS and use it as a base
5829 * timestamp for the trun entries.
5831 * To keep track of the current buffer timestamp and starting point
5832 * we use gst_adapter_prev_pts that gives us the PTS and the distance
5833 * from the beggining of the buffer, with the distance and demux->offset
5834 * we know if it is still the same buffer or not.
5836 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
5837 prev_offset = demux->offset - dist;
5838 if (demux->fragment_start_offset == -1
5839 || prev_offset > demux->fragment_start_offset) {
5840 demux->fragment_start_offset = prev_offset;
5841 demux->fragment_start = prev_pts;
5842 GST_DEBUG_OBJECT (demux,
5843 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
5844 GST_TIME_FORMAT, demux->fragment_start_offset,
5845 GST_TIME_ARGS (demux->fragment_start));
5848 demux->moof_offset = demux->offset;
5849 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
5850 demux->offset, NULL)) {
5851 gst_adapter_unmap (demux->adapter);
5852 ret = GST_FLOW_ERROR;
5855 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
5856 if (demux->mss_mode && !demux->exposed) {
5857 if (!demux->pending_newsegment) {
5859 gst_segment_init (&segment, GST_FORMAT_TIME);
5860 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
5861 demux->pending_newsegment = gst_event_new_segment (&segment);
5863 qtdemux_expose_streams (demux);
5866 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
5868 } else if (fourcc == FOURCC_ftyp) {
5869 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
5870 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
5871 } else if (fourcc == FOURCC_uuid) {
5872 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
5873 qtdemux_parse_uuid (demux, data, demux->neededbytes);
5874 } else if (fourcc == FOURCC_sidx) {
5875 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
5876 qtdemux_parse_sidx (demux, data, demux->neededbytes);
5878 GST_WARNING_OBJECT (demux,
5879 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
5880 GST_FOURCC_ARGS (fourcc));
5881 /* Let's jump that one and go back to initial state */
5883 gst_adapter_unmap (demux->adapter);
5886 if (demux->mdatbuffer && demux->n_streams) {
5887 gsize remaining_data_size = 0;
5889 /* the mdat was before the header */
5890 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
5891 demux->n_streams, demux->mdatbuffer);
5892 /* restore our adapter/offset view of things with upstream;
5893 * put preceding buffered data ahead of current moov data.
5894 * This should also handle evil mdat, moov, mdat cases and alike */
5895 gst_adapter_flush (demux->adapter, demux->neededbytes);
5897 /* Store any remaining data after the mdat for later usage */
5898 remaining_data_size = gst_adapter_available (demux->adapter);
5899 if (remaining_data_size > 0) {
5900 g_assert (demux->restoredata_buffer == NULL);
5901 demux->restoredata_buffer =
5902 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
5903 demux->restoredata_offset = demux->offset + demux->neededbytes;
5904 GST_DEBUG_OBJECT (demux,
5905 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
5906 G_GUINT64_FORMAT, remaining_data_size,
5907 demux->restoredata_offset);
5910 gst_adapter_push (demux->adapter, demux->mdatbuffer);
5911 demux->mdatbuffer = NULL;
5912 demux->offset = demux->mdatoffset;
5913 demux->neededbytes = next_entry_size (demux);
5914 demux->state = QTDEMUX_STATE_MOVIE;
5915 demux->mdatleft = gst_adapter_available (demux->adapter);
5917 GST_DEBUG_OBJECT (demux, "Carrying on normally");
5918 gst_adapter_flush (demux->adapter, demux->neededbytes);
5920 /* only go back to the mdat if there are samples to play */
5921 if (demux->got_moov && demux->first_mdat != -1
5922 && has_next_entry (demux)) {
5925 /* we need to seek back */
5926 res = qtdemux_seek_offset (demux, demux->first_mdat);
5928 demux->offset = demux->first_mdat;
5930 GST_DEBUG_OBJECT (demux, "Seek back failed");
5933 demux->offset += demux->neededbytes;
5935 demux->neededbytes = 16;
5936 demux->state = QTDEMUX_STATE_INITIAL;
5941 case QTDEMUX_STATE_BUFFER_MDAT:{
5945 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
5947 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
5948 gst_buffer_extract (buf, 0, fourcc, 4);
5949 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
5950 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
5951 if (demux->mdatbuffer)
5952 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
5954 demux->mdatbuffer = buf;
5955 demux->offset += demux->neededbytes;
5956 demux->neededbytes = 16;
5957 demux->state = QTDEMUX_STATE_INITIAL;
5958 gst_qtdemux_post_progress (demux, 1, 1);
5962 case QTDEMUX_STATE_MOVIE:{
5963 QtDemuxStream *stream = NULL;
5964 QtDemuxSample *sample;
5966 GstClockTime dts, pts, duration;
5969 GST_DEBUG_OBJECT (demux,
5970 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
5972 if (demux->fragmented) {
5973 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
5975 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
5976 /* if needed data starts within this atom,
5977 * then it should not exceed this atom */
5978 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
5979 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
5980 (_("This file is invalid and cannot be played.")),
5981 ("sample data crosses atom boundary"));
5982 ret = GST_FLOW_ERROR;
5985 demux->mdatleft -= demux->neededbytes;
5987 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
5988 /* so we are dropping more than left in this atom */
5989 gst_qtdemux_drop_data (demux, demux->mdatleft);
5990 demux->mdatleft = 0;
5992 /* need to resume atom parsing so we do not miss any other pieces */
5993 demux->state = QTDEMUX_STATE_INITIAL;
5994 demux->neededbytes = 16;
5996 /* check if there was any stored post mdat data from previous buffers */
5997 if (demux->restoredata_buffer) {
5998 g_assert (gst_adapter_available (demux->adapter) == 0);
6000 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
6001 demux->restoredata_buffer = NULL;
6002 demux->offset = demux->restoredata_offset;
6009 if (demux->todrop) {
6010 if (demux->cenc_aux_info_offset > 0) {
6014 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
6015 data = gst_adapter_map (demux->adapter, demux->todrop);
6016 gst_byte_reader_init (&br, data + 8, demux->todrop);
6017 if (!qtdemux_parse_cenc_aux_info (demux, demux->streams[0], &br,
6018 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
6019 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
6020 ret = GST_FLOW_ERROR;
6021 gst_adapter_unmap (demux->adapter);
6022 g_free (demux->cenc_aux_info_sizes);
6023 demux->cenc_aux_info_sizes = NULL;
6026 demux->cenc_aux_info_offset = 0;
6027 g_free (demux->cenc_aux_info_sizes);
6028 demux->cenc_aux_info_sizes = NULL;
6029 gst_adapter_unmap (demux->adapter);
6031 gst_qtdemux_drop_data (demux, demux->todrop);
6035 /* initial newsegment sent here after having added pads,
6036 * possible others in sink_event */
6037 gst_qtdemux_check_send_pending_segment (demux);
6039 /* Figure out which stream this packet belongs to */
6040 for (i = 0; i < demux->n_streams; i++) {
6041 stream = demux->streams[i];
6042 if (stream->sample_index >= stream->n_samples)
6044 GST_LOG_OBJECT (demux,
6045 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
6046 " / size:%d)", i, stream->sample_index,
6047 stream->samples[stream->sample_index].offset,
6048 stream->samples[stream->sample_index].size);
6050 if (stream->samples[stream->sample_index].offset == demux->offset)
6054 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
6055 goto unknown_stream;
6057 if (stream->new_caps) {
6058 gst_qtdemux_configure_stream (demux, stream);
6061 /* Put data in a buffer, set timestamps, caps, ... */
6062 sample = &stream->samples[stream->sample_index];
6064 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
6065 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
6066 GST_FOURCC_ARGS (stream->fourcc));
6068 dts = QTSAMPLE_DTS (stream, sample);
6069 pts = QTSAMPLE_PTS (stream, sample);
6070 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
6071 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
6073 /* check for segment end */
6074 if (G_UNLIKELY (demux->segment.stop != -1
6075 && demux->segment.stop <= pts && stream->on_keyframe)) {
6076 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
6077 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
6079 /* skip this data, stream is EOS */
6080 gst_adapter_flush (demux->adapter, demux->neededbytes);
6082 /* check if all streams are eos */
6084 for (i = 0; i < demux->n_streams; i++) {
6085 if (!STREAM_IS_EOS (demux->streams[i])) {
6091 if (ret == GST_FLOW_EOS) {
6092 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
6099 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6101 /* FIXME: should either be an assert or a plain check */
6102 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
6104 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
6105 dts, pts, duration, keyframe, dts, demux->offset);
6109 ret = gst_qtdemux_combine_flows (demux, stream, ret);
6111 /* skip this data, stream is EOS */
6112 gst_adapter_flush (demux->adapter, demux->neededbytes);
6115 stream->sample_index++;
6116 stream->offset_in_sample = 0;
6118 /* update current offset and figure out size of next buffer */
6119 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
6120 demux->offset, demux->neededbytes);
6121 demux->offset += demux->neededbytes;
6122 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
6125 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
6126 if (demux->fragmented) {
6127 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
6128 /* there may be more to follow, only finish this atom */
6129 demux->todrop = demux->mdatleft;
6130 demux->neededbytes = demux->todrop;
6142 /* when buffering movie data, at least show user something is happening */
6143 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
6144 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
6145 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
6146 demux->neededbytes);
6155 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
6156 ret = GST_FLOW_ERROR;
6161 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
6167 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
6168 (NULL), ("qtdemuxer invalid state %d", demux->state));
6169 ret = GST_FLOW_ERROR;
6174 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
6175 (NULL), ("no 'moov' atom within the first 10 MB"));
6176 ret = GST_FLOW_ERROR;
6182 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
6187 query = gst_query_new_scheduling ();
6189 if (!gst_pad_peer_query (sinkpad, query)) {
6190 gst_query_unref (query);
6194 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
6195 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
6196 gst_query_unref (query);
6201 GST_DEBUG_OBJECT (sinkpad, "activating pull");
6202 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
6206 GST_DEBUG_OBJECT (sinkpad, "activating push");
6207 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
6212 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
6213 GstPadMode mode, gboolean active)
6216 GstQTDemux *demux = GST_QTDEMUX (parent);
6219 case GST_PAD_MODE_PUSH:
6220 demux->pullbased = FALSE;
6223 case GST_PAD_MODE_PULL:
6225 demux->pullbased = TRUE;
6226 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
6229 res = gst_pad_stop_task (sinkpad);
6241 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
6243 return g_malloc (items * size);
6247 qtdemux_zfree (void *opaque, void *addr)
6253 qtdemux_inflate (void *z_buffer, guint z_length, guint length)
6259 z = g_new0 (z_stream, 1);
6260 z->zalloc = qtdemux_zalloc;
6261 z->zfree = qtdemux_zfree;
6264 z->next_in = z_buffer;
6265 z->avail_in = z_length;
6267 buffer = (guint8 *) g_malloc (length);
6268 ret = inflateInit (z);
6269 while (z->avail_in > 0) {
6270 if (z->avail_out == 0) {
6272 buffer = (guint8 *) g_realloc (buffer, length);
6273 z->next_out = buffer + z->total_out;
6274 z->avail_out = 1024;
6276 ret = inflate (z, Z_SYNC_FLUSH);
6280 if (ret != Z_STREAM_END) {
6281 g_warning ("inflate() returned %d", ret);
6287 #endif /* HAVE_ZLIB */
6290 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
6294 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
6296 /* counts as header data */
6297 qtdemux->header_size += length;
6299 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
6300 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
6302 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
6308 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
6309 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
6310 if (dcom == NULL || cmvd == NULL)
6311 goto invalid_compression;
6313 method = QT_FOURCC ((guint8 *) dcom->data + 8);
6316 case GST_MAKE_FOURCC ('z', 'l', 'i', 'b'):{
6317 guint uncompressed_length;
6318 guint compressed_length;
6321 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
6322 compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12;
6323 GST_LOG ("length = %u", uncompressed_length);
6326 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
6327 compressed_length, uncompressed_length);
6329 qtdemux->moov_node_compressed = qtdemux->moov_node;
6330 qtdemux->moov_node = g_node_new (buf);
6332 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
6333 uncompressed_length);
6336 #endif /* HAVE_ZLIB */
6338 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
6339 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
6346 invalid_compression:
6348 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
6354 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
6357 while (G_UNLIKELY (buf < end)) {
6361 if (G_UNLIKELY (buf + 4 > end)) {
6362 GST_LOG_OBJECT (qtdemux, "buffer overrun");
6365 len = QT_UINT32 (buf);
6366 if (G_UNLIKELY (len == 0)) {
6367 GST_LOG_OBJECT (qtdemux, "empty container");
6370 if (G_UNLIKELY (len < 8)) {
6371 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
6374 if (G_UNLIKELY (len > (end - buf))) {
6375 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
6376 (gint) (end - buf));
6380 child = g_node_new ((guint8 *) buf);
6381 g_node_append (node, child);
6382 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
6383 qtdemux_parse_node (qtdemux, child, buf, len);
6391 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
6394 int len = QT_UINT32 (xdxt->data);
6395 guint8 *buf = xdxt->data;
6396 guint8 *end = buf + len;
6399 /* skip size and type */
6407 size = QT_UINT32 (buf);
6408 type = QT_FOURCC (buf + 4);
6410 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
6412 if (buf + size > end || size <= 0)
6418 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
6419 GST_FOURCC_ARGS (type));
6423 buffer = gst_buffer_new_and_alloc (size);
6424 gst_buffer_fill (buffer, 0, buf, size);
6425 stream->buffers = g_slist_append (stream->buffers, buffer);
6426 GST_LOG_OBJECT (qtdemux, "parsing theora header");
6429 buffer = gst_buffer_new_and_alloc (size);
6430 gst_buffer_fill (buffer, 0, buf, size);
6431 stream->buffers = g_slist_append (stream->buffers, buffer);
6432 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
6435 buffer = gst_buffer_new_and_alloc (size);
6436 gst_buffer_fill (buffer, 0, buf, size);
6437 stream->buffers = g_slist_append (stream->buffers, buffer);
6438 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
6441 GST_WARNING_OBJECT (qtdemux,
6442 "unknown theora cookie %" GST_FOURCC_FORMAT,
6443 GST_FOURCC_ARGS (type));
6452 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
6456 guint32 node_length = 0;
6457 const QtNodeType *type;
6460 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
6462 if (G_UNLIKELY (length < 8))
6463 goto not_enough_data;
6465 node_length = QT_UINT32 (buffer);
6466 fourcc = QT_FOURCC (buffer + 4);
6468 /* ignore empty nodes */
6469 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
6472 type = qtdemux_type_get (fourcc);
6474 end = buffer + length;
6476 GST_LOG_OBJECT (qtdemux,
6477 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
6478 GST_FOURCC_ARGS (fourcc), node_length, type->name);
6480 if (node_length > length)
6481 goto broken_atom_size;
6483 if (type->flags & QT_FLAG_CONTAINER) {
6484 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
6489 if (node_length < 20) {
6490 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
6493 GST_DEBUG_OBJECT (qtdemux,
6494 "parsing stsd (sample table, sample description) atom");
6495 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
6496 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
6506 /* also read alac (or whatever) in stead of mp4a in the following,
6507 * since a similar layout is used in other cases as well */
6508 if (fourcc == FOURCC_mp4a)
6513 /* There are two things we might encounter here: a true mp4a atom, and
6514 an mp4a entry in an stsd atom. The latter is what we're interested
6515 in, and it looks like an atom, but isn't really one. The true mp4a
6516 atom is short, so we detect it based on length here. */
6517 if (length < min_size) {
6518 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
6519 GST_FOURCC_ARGS (fourcc));
6523 /* 'version' here is the sound sample description version. Types 0 and
6524 1 are documented in the QTFF reference, but type 2 is not: it's
6525 described in Apple header files instead (struct SoundDescriptionV2
6527 version = QT_UINT16 (buffer + 16);
6529 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
6530 GST_FOURCC_ARGS (fourcc), version);
6532 /* parse any esds descriptors */
6544 GST_WARNING_OBJECT (qtdemux,
6545 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
6546 GST_FOURCC_ARGS (fourcc), version);
6551 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
6568 /* codec_data is contained inside these atoms, which all have
6569 * the same format. */
6571 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
6572 GST_FOURCC_ARGS (fourcc));
6573 version = QT_UINT32 (buffer + 16);
6574 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
6575 if (1 || version == 0x00000000) {
6576 buf = buffer + 0x32;
6578 /* FIXME Quicktime uses PASCAL string while
6579 * the iso format uses C strings. Check the file
6580 * type before attempting to parse the string here. */
6581 tlen = QT_UINT8 (buf);
6582 GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
6584 GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
6585 /* the string has a reserved space of 32 bytes so skip
6586 * the remaining 31 */
6588 buf += 4; /* and 4 bytes reserved */
6590 GST_MEMDUMP_OBJECT (qtdemux, "mp4v", buf, end - buf);
6592 qtdemux_parse_container (qtdemux, node, buf, end);
6598 GST_MEMDUMP_OBJECT (qtdemux, "H264", buffer, end - buffer);
6599 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6604 GST_MEMDUMP_OBJECT (qtdemux, "avc1", buffer, end - buffer);
6605 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6610 GST_MEMDUMP_OBJECT (qtdemux, "avc3", buffer, end - buffer);
6611 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6616 GST_MEMDUMP_OBJECT (qtdemux, "H265", buffer, end - buffer);
6617 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6622 GST_MEMDUMP_OBJECT (qtdemux, "hvc1", buffer, end - buffer);
6623 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6628 GST_MEMDUMP_OBJECT (qtdemux, "hev1", buffer, end - buffer);
6629 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6634 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
6639 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
6640 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
6645 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
6646 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
6647 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
6655 version = QT_UINT32 (buffer + 12);
6656 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
6663 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
6668 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
6673 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
6678 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
6683 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
6688 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
6692 if (!strcmp (type->name, "unknown"))
6693 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
6697 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
6698 GST_FOURCC_ARGS (fourcc));
6704 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
6705 (_("This file is corrupt and cannot be played.")),
6706 ("Not enough data for an atom header, got only %u bytes", length));
6711 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
6712 (_("This file is corrupt and cannot be played.")),
6713 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
6714 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
6721 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
6725 guint32 child_fourcc;
6727 for (child = g_node_first_child (node); child;
6728 child = g_node_next_sibling (child)) {
6729 buffer = (guint8 *) child->data;
6731 child_fourcc = QT_FOURCC (buffer + 4);
6733 if (G_UNLIKELY (child_fourcc == fourcc)) {
6741 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
6742 GstByteReader * parser)
6746 guint32 child_fourcc, child_len;
6748 for (child = g_node_first_child (node); child;
6749 child = g_node_next_sibling (child)) {
6750 buffer = (guint8 *) child->data;
6752 child_len = QT_UINT32 (buffer);
6753 child_fourcc = QT_FOURCC (buffer + 4);
6755 if (G_UNLIKELY (child_fourcc == fourcc)) {
6756 if (G_UNLIKELY (child_len < (4 + 4)))
6758 /* FIXME: must verify if atom length < parent atom length */
6759 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
6767 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
6768 GstByteReader * parser)
6772 guint32 child_fourcc, child_len;
6774 for (child = g_node_next_sibling (node); child;
6775 child = g_node_next_sibling (child)) {
6776 buffer = (guint8 *) child->data;
6778 child_fourcc = QT_FOURCC (buffer + 4);
6780 if (child_fourcc == fourcc) {
6782 child_len = QT_UINT32 (buffer);
6783 if (G_UNLIKELY (child_len < (4 + 4)))
6785 /* FIXME: must verify if atom length < parent atom length */
6786 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
6795 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
6797 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
6801 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
6803 /* FIXME: This can only reliably work if demuxers have a
6804 * separate streaming thread per srcpad. This should be
6805 * done in a demuxer base class, which integrates parts
6808 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
6813 query = gst_query_new_allocation (stream->caps, FALSE);
6815 if (!gst_pad_peer_query (stream->pad, query)) {
6816 /* not a problem, just debug a little */
6817 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
6820 if (stream->allocator)
6821 gst_object_unref (stream->allocator);
6823 if (gst_query_get_n_allocation_params (query) > 0) {
6824 /* try the allocator */
6825 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
6827 stream->use_allocator = TRUE;
6829 stream->allocator = NULL;
6830 gst_allocation_params_init (&stream->params);
6831 stream->use_allocator = FALSE;
6833 gst_query_unref (query);
6838 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
6839 QtDemuxStream * stream)
6842 const gchar *selected_system;
6844 g_return_val_if_fail (qtdemux != NULL, FALSE);
6845 g_return_val_if_fail (stream != NULL, FALSE);
6846 g_return_val_if_fail (gst_caps_get_size (stream->caps) == 1, FALSE);
6848 if (stream->protection_scheme_type != FOURCC_cenc) {
6849 GST_ERROR_OBJECT (qtdemux, "unsupported protection scheme");
6852 if (qtdemux->protection_system_ids == NULL) {
6853 GST_ERROR_OBJECT (qtdemux, "stream is protected using cenc, but no "
6854 "cenc protection system information has been found");
6857 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
6858 selected_system = gst_protection_select_system ((const gchar **)
6859 qtdemux->protection_system_ids->pdata);
6860 g_ptr_array_remove_index (qtdemux->protection_system_ids,
6861 qtdemux->protection_system_ids->len - 1);
6862 if (!selected_system) {
6863 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
6864 "suitable decryptor element has been found");
6868 s = gst_caps_get_structure (stream->caps, 0);
6869 gst_structure_set (s,
6870 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
6871 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
6873 gst_structure_set_name (s, "application/x-cenc");
6878 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
6880 if (stream->subtype == FOURCC_vide) {
6881 /* fps is calculated base on the duration of the average framerate since
6882 * qt does not have a fixed framerate. */
6883 if ((stream->n_samples == 1) && (stream->first_duration == 0)) {
6888 if (stream->duration == 0 || stream->n_samples < 2) {
6889 stream->fps_n = stream->timescale;
6892 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
6893 /* stream->duration is guint64, timescale, n_samples are guint32 */
6894 GstClockTime avg_duration =
6895 gst_util_uint64_scale_round (stream->duration -
6896 stream->first_duration, GST_SECOND,
6897 (guint64) (stream->timescale) * (stream->n_samples - 1));
6899 GST_LOG_OBJECT (qtdemux,
6900 "Calculating avg sample duration based on stream duration %"
6902 " minus first sample %u, leaving %d samples gives %"
6903 GST_TIME_FORMAT, stream->duration, stream->first_duration,
6904 stream->n_samples - 1, GST_TIME_ARGS (avg_duration));
6906 gst_video_guess_framerate (avg_duration, &stream->fps_n,
6909 GST_DEBUG_OBJECT (qtdemux,
6910 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
6911 stream->timescale, stream->fps_n, stream->fps_d);
6915 stream->caps = gst_caps_make_writable (stream->caps);
6917 gst_caps_set_simple (stream->caps,
6918 "width", G_TYPE_INT, stream->width,
6919 "height", G_TYPE_INT, stream->height,
6920 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
6922 /* calculate pixel-aspect-ratio using display width and height */
6923 GST_DEBUG_OBJECT (qtdemux,
6924 "video size %dx%d, target display size %dx%d", stream->width,
6925 stream->height, stream->display_width, stream->display_height);
6926 /* qt file might have pasp atom */
6927 if (stream->par_w > 0 && stream->par_h > 0) {
6928 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
6929 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
6930 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
6931 } else if (stream->display_width > 0 && stream->display_height > 0 &&
6932 stream->width > 0 && stream->height > 0) {
6935 /* calculate the pixel aspect ratio using the display and pixel w/h */
6936 n = stream->display_width * stream->height;
6937 d = stream->display_height * stream->width;
6940 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
6943 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
6944 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
6947 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
6948 guint par_w = 1, par_h = 1;
6950 if (stream->par_w > 0 && stream->par_h > 0) {
6951 par_w = stream->par_w;
6952 par_h = stream->par_h;
6955 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
6956 stream->width, stream->height, par_w, par_h)) {
6957 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
6960 gst_caps_set_simple (stream->caps,
6961 "multiview-mode", G_TYPE_STRING,
6962 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
6963 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
6964 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
6969 else if (stream->subtype == FOURCC_soun) {
6971 stream->caps = gst_caps_make_writable (stream->caps);
6972 if (stream->rate > 0)
6973 gst_caps_set_simple (stream->caps,
6974 "rate", G_TYPE_INT, (int) stream->rate, NULL);
6975 if (stream->n_channels > 0)
6976 gst_caps_set_simple (stream->caps,
6977 "channels", G_TYPE_INT, stream->n_channels, NULL);
6978 if (stream->n_channels > 2) {
6979 /* FIXME: Need to parse the 'chan' atom to get channel layouts
6980 * correctly; this is just the minimum we can do - assume
6981 * we don't actually have any channel positions. */
6982 gst_caps_set_simple (stream->caps,
6983 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
6989 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
6990 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
6991 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
6992 gst_pad_set_active (stream->pad, TRUE);
6994 gst_pad_use_fixed_caps (stream->pad);
6996 if (stream->protected) {
6997 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
6998 GST_ERROR_OBJECT (qtdemux,
6999 "Failed to configure protected stream caps.");
7004 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
7005 if (stream->new_stream) {
7008 GstStreamFlags stream_flags;
7011 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
7014 if (gst_event_parse_group_id (event, &qtdemux->group_id))
7015 qtdemux->have_group_id = TRUE;
7017 qtdemux->have_group_id = FALSE;
7018 gst_event_unref (event);
7019 } else if (!qtdemux->have_group_id) {
7020 qtdemux->have_group_id = TRUE;
7021 qtdemux->group_id = gst_util_group_id_next ();
7024 stream->new_stream = FALSE;
7026 gst_pad_create_stream_id_printf (stream->pad,
7027 GST_ELEMENT_CAST (qtdemux), "%03u", stream->track_id);
7028 event = gst_event_new_stream_start (stream_id);
7029 if (qtdemux->have_group_id)
7030 gst_event_set_group_id (event, qtdemux->group_id);
7031 stream_flags = GST_STREAM_FLAG_NONE;
7032 if (stream->disabled)
7033 stream_flags |= GST_STREAM_FLAG_UNSELECT;
7035 stream_flags |= GST_STREAM_FLAG_SPARSE;
7036 gst_event_set_stream_flags (event, stream_flags);
7037 gst_pad_push_event (stream->pad, event);
7040 gst_pad_set_caps (stream->pad, stream->caps);
7041 stream->new_caps = FALSE;
7047 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
7048 QtDemuxStream * stream, GstTagList * list)
7050 /* consistent default for push based mode */
7051 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
7053 if (stream->subtype == FOURCC_vide) {
7054 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
7057 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
7060 gst_qtdemux_configure_stream (qtdemux, stream);
7061 qtdemux->n_video_streams++;
7062 } else if (stream->subtype == FOURCC_soun) {
7063 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
7066 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
7068 gst_qtdemux_configure_stream (qtdemux, stream);
7069 qtdemux->n_audio_streams++;
7070 } else if (stream->subtype == FOURCC_strm) {
7071 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
7072 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
7073 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
7074 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
7077 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
7079 gst_qtdemux_configure_stream (qtdemux, stream);
7080 qtdemux->n_sub_streams++;
7081 } else if (stream->caps) {
7082 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
7085 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
7087 gst_qtdemux_configure_stream (qtdemux, stream);
7088 qtdemux->n_video_streams++;
7090 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
7097 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
7098 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
7099 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
7100 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
7102 if (stream->pending_tags)
7103 gst_tag_list_unref (stream->pending_tags);
7104 stream->pending_tags = list;
7106 /* global tags go on each pad anyway */
7107 stream->send_global_tags = TRUE;
7108 /* send upstream GST_EVENT_PROTECTION events that were received before
7109 this source pad was created */
7110 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
7111 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
7115 gst_tag_list_unref (list);
7119 /* find next atom with @fourcc starting at @offset */
7120 static GstFlowReturn
7121 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
7122 guint64 * length, guint32 fourcc)
7128 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
7129 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
7135 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
7136 if (G_UNLIKELY (ret != GST_FLOW_OK))
7138 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
7141 gst_buffer_unref (buf);
7144 gst_buffer_map (buf, &map, GST_MAP_READ);
7145 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
7146 gst_buffer_unmap (buf, &map);
7147 gst_buffer_unref (buf);
7149 if (G_UNLIKELY (*length == 0)) {
7150 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
7151 ret = GST_FLOW_ERROR;
7155 if (lfourcc == fourcc) {
7156 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
7160 GST_LOG_OBJECT (qtdemux,
7161 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
7162 GST_FOURCC_ARGS (fourcc), *offset);
7171 /* might simply have had last one */
7172 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
7177 /* should only do something in pull mode */
7178 /* call with OBJECT lock */
7179 static GstFlowReturn
7180 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
7182 guint64 length, offset;
7183 GstBuffer *buf = NULL;
7184 GstFlowReturn ret = GST_FLOW_OK;
7185 GstFlowReturn res = GST_FLOW_OK;
7188 offset = qtdemux->moof_offset;
7189 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
7192 GST_DEBUG_OBJECT (qtdemux, "no next moof");
7193 return GST_FLOW_EOS;
7196 /* best not do pull etc with lock held */
7197 GST_OBJECT_UNLOCK (qtdemux);
7199 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
7200 if (ret != GST_FLOW_OK)
7203 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
7204 if (G_UNLIKELY (ret != GST_FLOW_OK))
7206 gst_buffer_map (buf, &map, GST_MAP_READ);
7207 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
7208 gst_buffer_unmap (buf, &map);
7209 gst_buffer_unref (buf);
7214 gst_buffer_unmap (buf, &map);
7215 gst_buffer_unref (buf);
7219 /* look for next moof */
7220 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
7221 if (G_UNLIKELY (ret != GST_FLOW_OK))
7225 GST_OBJECT_LOCK (qtdemux);
7227 qtdemux->moof_offset = offset;
7233 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
7235 res = GST_FLOW_ERROR;
7240 /* maybe upstream temporarily flushing */
7241 if (ret != GST_FLOW_FLUSHING) {
7242 GST_DEBUG_OBJECT (qtdemux, "no next moof");
7245 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
7246 /* resume at current position next time */
7253 /* initialise bytereaders for stbl sub-atoms */
7255 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
7257 stream->stbl_index = -1; /* no samples have yet been parsed */
7258 stream->sample_index = -1;
7260 /* time-to-sample atom */
7261 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
7264 /* copy atom data into a new buffer for later use */
7265 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
7267 /* skip version + flags */
7268 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
7269 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
7271 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
7273 /* make sure there's enough data */
7274 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
7275 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
7276 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
7277 stream->n_sample_times);
7278 if (!stream->n_sample_times)
7282 /* sync sample atom */
7283 stream->stps_present = FALSE;
7284 if ((stream->stss_present =
7285 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
7286 &stream->stss) ? TRUE : FALSE) == TRUE) {
7287 /* copy atom data into a new buffer for later use */
7288 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
7290 /* skip version + flags */
7291 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
7292 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
7295 if (stream->n_sample_syncs) {
7296 /* make sure there's enough data */
7297 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
7301 /* partial sync sample atom */
7302 if ((stream->stps_present =
7303 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
7304 &stream->stps) ? TRUE : FALSE) == TRUE) {
7305 /* copy atom data into a new buffer for later use */
7306 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
7308 /* skip version + flags */
7309 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
7310 !gst_byte_reader_get_uint32_be (&stream->stps,
7311 &stream->n_sample_partial_syncs))
7314 /* if there are no entries, the stss table contains the real
7316 if (stream->n_sample_partial_syncs) {
7317 /* make sure there's enough data */
7318 if (!qt_atom_parser_has_chunks (&stream->stps,
7319 stream->n_sample_partial_syncs, 4))
7326 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
7329 /* copy atom data into a new buffer for later use */
7330 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
7332 /* skip version + flags */
7333 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
7334 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
7337 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
7340 if (!stream->n_samples)
7343 /* sample-to-chunk atom */
7344 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
7347 /* copy atom data into a new buffer for later use */
7348 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
7350 /* skip version + flags */
7351 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
7352 !gst_byte_reader_get_uint32_be (&stream->stsc,
7353 &stream->n_samples_per_chunk))
7356 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
7357 stream->n_samples_per_chunk);
7359 /* make sure there's enough data */
7360 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
7366 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
7367 stream->co_size = sizeof (guint32);
7368 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
7370 stream->co_size = sizeof (guint64);
7374 /* copy atom data into a new buffer for later use */
7375 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
7377 /* skip version + flags */
7378 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
7381 /* chunks_are_samples == TRUE means treat chunks as samples */
7382 stream->chunks_are_samples = stream->sample_size && !stream->sampled;
7383 if (stream->chunks_are_samples) {
7384 /* treat chunks as samples */
7385 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
7388 /* skip number of entries */
7389 if (!gst_byte_reader_skip (&stream->stco, 4))
7392 /* make sure there are enough data in the stsz atom */
7393 if (!stream->sample_size) {
7394 /* different sizes for each sample */
7395 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
7400 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
7401 stream->n_samples, (guint) sizeof (QtDemuxSample),
7402 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
7404 if (stream->n_samples >=
7405 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
7406 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
7407 "be larger than %uMB (broken file?)", stream->n_samples,
7408 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
7412 g_assert (stream->samples == NULL);
7413 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
7414 if (!stream->samples) {
7415 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
7420 /* composition time-to-sample */
7421 if ((stream->ctts_present =
7422 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
7423 &stream->ctts) ? TRUE : FALSE) == TRUE) {
7424 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
7426 /* copy atom data into a new buffer for later use */
7427 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
7429 /* skip version + flags */
7430 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
7431 || !gst_byte_reader_get_uint32_be (&stream->ctts,
7432 &stream->n_composition_times))
7435 /* make sure there's enough data */
7436 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
7440 /* This is optional, if missing we iterate the ctts */
7441 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
7442 if (!gst_byte_reader_skip (&cslg, 1 + 3)
7443 || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
7444 g_free ((gpointer) cslg.data);
7448 gint32 cslg_least = 0;
7449 guint num_entries, pos;
7452 pos = gst_byte_reader_get_pos (&stream->ctts);
7453 num_entries = stream->n_composition_times;
7455 stream->cslg_shift = 0;
7457 for (i = 0; i < num_entries; i++) {
7460 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
7461 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
7463 if (offset < cslg_least)
7464 cslg_least = offset;
7468 stream->cslg_shift = ABS (cslg_least);
7470 stream->cslg_shift = 0;
7472 /* reset the reader so we can generate sample table */
7473 gst_byte_reader_set_pos (&stream->ctts, pos);
7476 /* Ensure the cslg_shift value is consistent so we can use it
7477 * unconditionnally to produce TS and Segment */
7478 stream->cslg_shift = 0;
7485 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7486 (_("This file is corrupt and cannot be played.")), (NULL));
7491 gst_qtdemux_stbl_free (stream);
7492 if (!qtdemux->fragmented) {
7493 /* not quite good */
7494 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
7497 /* may pick up samples elsewhere */
7503 /* collect samples from the next sample to be parsed up to sample @n for @stream
7504 * by reading the info from @stbl
7506 * This code can be executed from both the streaming thread and the seeking
7507 * thread so it takes the object lock to protect itself
7510 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
7513 QtDemuxSample *samples, *first, *cur, *last;
7514 guint32 n_samples_per_chunk;
7517 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
7518 GST_FOURCC_FORMAT ", pad %s", GST_FOURCC_ARGS (stream->fourcc),
7519 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
7521 n_samples = stream->n_samples;
7524 goto out_of_samples;
7526 GST_OBJECT_LOCK (qtdemux);
7527 if (n <= stream->stbl_index)
7528 goto already_parsed;
7530 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
7532 if (!stream->stsz.data) {
7533 /* so we already parsed and passed all the moov samples;
7534 * onto fragmented ones */
7535 g_assert (qtdemux->fragmented);
7539 /* pointer to the sample table */
7540 samples = stream->samples;
7542 /* starts from -1, moves to the next sample index to parse */
7543 stream->stbl_index++;
7545 /* keep track of the first and last sample to fill */
7546 first = &samples[stream->stbl_index];
7549 if (!stream->chunks_are_samples) {
7550 /* set the sample sizes */
7551 if (stream->sample_size == 0) {
7552 /* different sizes for each sample */
7553 for (cur = first; cur <= last; cur++) {
7554 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
7555 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
7556 (guint) (cur - samples), cur->size);
7559 /* samples have the same size */
7560 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
7561 for (cur = first; cur <= last; cur++)
7562 cur->size = stream->sample_size;
7566 n_samples_per_chunk = stream->n_samples_per_chunk;
7569 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
7572 if (stream->stsc_chunk_index >= stream->last_chunk
7573 || stream->stsc_chunk_index < stream->first_chunk) {
7574 stream->first_chunk =
7575 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
7576 stream->samples_per_chunk =
7577 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
7578 gst_byte_reader_skip_unchecked (&stream->stsc, 4);
7580 /* chunk numbers are counted from 1 it seems */
7581 if (G_UNLIKELY (stream->first_chunk == 0))
7584 --stream->first_chunk;
7586 /* the last chunk of each entry is calculated by taking the first chunk
7587 * of the next entry; except if there is no next, where we fake it with
7589 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
7590 stream->last_chunk = G_MAXUINT32;
7592 stream->last_chunk =
7593 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
7594 if (G_UNLIKELY (stream->last_chunk == 0))
7597 --stream->last_chunk;
7600 GST_LOG_OBJECT (qtdemux,
7601 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
7602 stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
7604 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
7607 if (stream->last_chunk != G_MAXUINT32) {
7608 if (!qt_atom_parser_peek_sub (&stream->stco,
7609 stream->first_chunk * stream->co_size,
7610 (stream->last_chunk - stream->first_chunk) * stream->co_size,
7615 stream->co_chunk = stream->stco;
7616 if (!gst_byte_reader_skip (&stream->co_chunk,
7617 stream->first_chunk * stream->co_size))
7621 stream->stsc_chunk_index = stream->first_chunk;
7624 last_chunk = stream->last_chunk;
7626 if (stream->chunks_are_samples) {
7627 cur = &samples[stream->stsc_chunk_index];
7629 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
7632 stream->stsc_chunk_index = j;
7637 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
7640 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
7641 "%" G_GUINT64_FORMAT, j, cur->offset);
7643 if (stream->samples_per_frame * stream->bytes_per_frame) {
7645 (stream->samples_per_chunk * stream->n_channels) /
7646 stream->samples_per_frame * stream->bytes_per_frame;
7648 cur->size = stream->samples_per_chunk;
7651 GST_DEBUG_OBJECT (qtdemux,
7652 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
7653 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
7654 stream->stco_sample_index)), cur->size);
7656 cur->timestamp = stream->stco_sample_index;
7657 cur->duration = stream->samples_per_chunk;
7658 cur->keyframe = TRUE;
7661 stream->stco_sample_index += stream->samples_per_chunk;
7663 stream->stsc_chunk_index = j;
7665 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
7666 guint32 samples_per_chunk;
7667 guint64 chunk_offset;
7669 if (!stream->stsc_sample_index
7670 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
7671 &stream->chunk_offset))
7674 samples_per_chunk = stream->samples_per_chunk;
7675 chunk_offset = stream->chunk_offset;
7677 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
7678 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
7679 G_GUINT64_FORMAT " and size %d",
7680 (guint) (cur - samples), chunk_offset, cur->size);
7682 cur->offset = chunk_offset;
7683 chunk_offset += cur->size;
7686 if (G_UNLIKELY (cur > last)) {
7688 stream->stsc_sample_index = k + 1;
7689 stream->chunk_offset = chunk_offset;
7690 stream->stsc_chunk_index = j;
7694 stream->stsc_sample_index = 0;
7696 stream->stsc_chunk_index = j;
7698 stream->stsc_index++;
7701 if (stream->chunks_are_samples)
7705 guint32 n_sample_times;
7707 n_sample_times = stream->n_sample_times;
7710 for (i = stream->stts_index; i < n_sample_times; i++) {
7711 guint32 stts_samples;
7712 gint32 stts_duration;
7715 if (stream->stts_sample_index >= stream->stts_samples
7716 || !stream->stts_sample_index) {
7718 stream->stts_samples =
7719 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
7720 stream->stts_duration =
7721 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
7723 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
7724 i, stream->stts_samples, stream->stts_duration);
7726 stream->stts_sample_index = 0;
7729 stts_samples = stream->stts_samples;
7730 stts_duration = stream->stts_duration;
7731 stts_time = stream->stts_time;
7733 for (j = stream->stts_sample_index; j < stts_samples; j++) {
7734 GST_DEBUG_OBJECT (qtdemux,
7735 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
7736 (guint) (cur - samples), j,
7737 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
7739 cur->timestamp = stts_time;
7740 cur->duration = stts_duration;
7742 /* avoid 32-bit wrap-around,
7743 * but still mind possible 'negative' duration */
7744 stts_time += (gint64) stts_duration;
7747 if (G_UNLIKELY (cur > last)) {
7749 stream->stts_time = stts_time;
7750 stream->stts_sample_index = j + 1;
7754 stream->stts_sample_index = 0;
7755 stream->stts_time = stts_time;
7756 stream->stts_index++;
7758 /* fill up empty timestamps with the last timestamp, this can happen when
7759 * the last samples do not decode and so we don't have timestamps for them.
7760 * We however look at the last timestamp to estimate the track length so we
7761 * need something in here. */
7762 for (; cur < last; cur++) {
7763 GST_DEBUG_OBJECT (qtdemux,
7764 "fill sample %d: timestamp %" GST_TIME_FORMAT,
7765 (guint) (cur - samples),
7766 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
7767 cur->timestamp = stream->stts_time;
7773 /* sample sync, can be NULL */
7774 if (stream->stss_present == TRUE) {
7775 guint32 n_sample_syncs;
7777 n_sample_syncs = stream->n_sample_syncs;
7779 if (!n_sample_syncs) {
7780 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
7781 stream->all_keyframe = TRUE;
7783 for (i = stream->stss_index; i < n_sample_syncs; i++) {
7784 /* note that the first sample is index 1, not 0 */
7787 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
7789 if (G_LIKELY (index > 0 && index <= n_samples)) {
7791 samples[index].keyframe = TRUE;
7792 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
7793 /* and exit if we have enough samples */
7794 if (G_UNLIKELY (index >= n)) {
7801 stream->stss_index = i;
7804 /* stps marks partial sync frames like open GOP I-Frames */
7805 if (stream->stps_present == TRUE) {
7806 guint32 n_sample_partial_syncs;
7808 n_sample_partial_syncs = stream->n_sample_partial_syncs;
7810 /* if there are no entries, the stss table contains the real
7812 if (n_sample_partial_syncs) {
7813 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
7814 /* note that the first sample is index 1, not 0 */
7817 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
7819 if (G_LIKELY (index > 0 && index <= n_samples)) {
7821 samples[index].keyframe = TRUE;
7822 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
7823 /* and exit if we have enough samples */
7824 if (G_UNLIKELY (index >= n)) {
7831 stream->stps_index = i;
7835 /* no stss, all samples are keyframes */
7836 stream->all_keyframe = TRUE;
7837 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
7842 /* composition time to sample */
7843 if (stream->ctts_present == TRUE) {
7844 guint32 n_composition_times;
7846 gint32 ctts_soffset;
7848 /* Fill in the pts_offsets */
7850 n_composition_times = stream->n_composition_times;
7852 for (i = stream->ctts_index; i < n_composition_times; i++) {
7853 if (stream->ctts_sample_index >= stream->ctts_count
7854 || !stream->ctts_sample_index) {
7855 stream->ctts_count =
7856 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
7857 stream->ctts_soffset =
7858 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
7859 stream->ctts_sample_index = 0;
7862 ctts_count = stream->ctts_count;
7863 ctts_soffset = stream->ctts_soffset;
7865 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
7866 cur->pts_offset = ctts_soffset;
7869 if (G_UNLIKELY (cur > last)) {
7871 stream->ctts_sample_index = j + 1;
7875 stream->ctts_sample_index = 0;
7876 stream->ctts_index++;
7880 stream->stbl_index = n;
7881 /* if index has been completely parsed, free data that is no-longer needed */
7882 if (n + 1 == stream->n_samples) {
7883 gst_qtdemux_stbl_free (stream);
7884 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
7885 if (qtdemux->pullbased) {
7886 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
7887 while (n + 1 == stream->n_samples)
7888 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
7892 GST_OBJECT_UNLOCK (qtdemux);
7899 GST_LOG_OBJECT (qtdemux,
7900 "Tried to parse up to sample %u but this sample has already been parsed",
7902 /* if fragmented, there may be more */
7903 if (qtdemux->fragmented && n == stream->stbl_index)
7905 GST_OBJECT_UNLOCK (qtdemux);
7911 GST_LOG_OBJECT (qtdemux,
7912 "Tried to parse up to sample %u but there are only %u samples", n + 1,
7914 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7915 (_("This file is corrupt and cannot be played.")), (NULL));
7920 GST_OBJECT_UNLOCK (qtdemux);
7921 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7922 (_("This file is corrupt and cannot be played.")), (NULL));
7927 /* collect all segment info for @stream.
7930 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
7934 /* accept edts if they contain gaps at start and there is only
7935 * one media segment */
7936 gboolean allow_pushbased_edts = TRUE;
7937 gint media_segments_count = 0;
7939 /* parse and prepare segment info from the edit list */
7940 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
7941 stream->n_segments = 0;
7942 stream->segments = NULL;
7943 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
7951 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
7952 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
7955 buffer = elst->data;
7957 n_segments = QT_UINT32 (buffer + 12);
7959 /* we might allocate a bit too much, at least allocate 1 segment */
7960 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
7962 /* segments always start from 0 */
7966 for (i = 0; i < n_segments; i++) {
7969 QtDemuxSegment *segment;
7972 media_time = QT_UINT32 (buffer + 20 + i * 12);
7973 duration = QT_UINT32 (buffer + 16 + i * 12);
7975 segment = &stream->segments[count++];
7977 /* time and duration expressed in global timescale */
7978 segment->time = stime;
7979 /* add non scaled values so we don't cause roundoff errors */
7981 stime = QTTIME_TO_GSTTIME (qtdemux, time);
7982 segment->stop_time = stime;
7983 segment->duration = stime - segment->time;
7985 segment->trak_media_start = media_time;
7986 /* media_time expressed in stream timescale */
7987 if (media_time != G_MAXUINT32) {
7988 segment->media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
7989 segment->media_stop = segment->media_start + segment->duration;
7990 media_segments_count++;
7992 segment->media_start = GST_CLOCK_TIME_NONE;
7993 segment->media_stop = GST_CLOCK_TIME_NONE;
7995 rate_int = GST_READ_UINT32_BE (buffer + 24 + i * 12);
7997 if (rate_int <= 1) {
7998 /* 0 is not allowed, some programs write 1 instead of the floating point
8000 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
8004 segment->rate = rate_int / 65536.0;
8007 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
8008 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
8009 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
8010 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
8011 i, GST_TIME_ARGS (segment->time),
8012 GST_TIME_ARGS (segment->duration),
8013 GST_TIME_ARGS (segment->media_start), media_time,
8014 GST_TIME_ARGS (segment->media_stop),
8015 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
8017 if (segment->stop_time > qtdemux->segment.stop) {
8018 GST_WARNING_OBJECT (qtdemux, "Segment %d "
8019 " extends to %" GST_TIME_FORMAT
8020 " past the end of the file duration %" GST_TIME_FORMAT
8021 " it will be truncated", i, GST_TIME_ARGS (segment->stop_time),
8022 GST_TIME_ARGS (qtdemux->segment.stop));
8023 qtdemux->segment.stop = segment->stop_time;
8026 GST_DEBUG_OBJECT (qtdemux, "found %d segments", count);
8027 stream->n_segments = count;
8028 if (media_segments_count != 1)
8029 allow_pushbased_edts = FALSE;
8033 /* push based does not handle segments, so act accordingly here,
8034 * and warn if applicable */
8035 if (!qtdemux->pullbased && !allow_pushbased_edts) {
8036 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
8037 /* remove and use default one below, we stream like it anyway */
8038 g_free (stream->segments);
8039 stream->segments = NULL;
8040 stream->n_segments = 0;
8043 /* no segments, create one to play the complete trak */
8044 if (stream->n_segments == 0) {
8045 GstClockTime stream_duration =
8046 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
8048 if (stream->segments == NULL)
8049 stream->segments = g_new (QtDemuxSegment, 1);
8051 /* represent unknown our way */
8052 if (stream_duration == 0)
8053 stream_duration = GST_CLOCK_TIME_NONE;
8055 stream->segments[0].time = 0;
8056 stream->segments[0].stop_time = stream_duration;
8057 stream->segments[0].duration = stream_duration;
8058 stream->segments[0].media_start = 0;
8059 stream->segments[0].media_stop = stream_duration;
8060 stream->segments[0].rate = 1.0;
8061 stream->segments[0].trak_media_start = 0;
8063 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
8064 GST_TIME_ARGS (stream_duration));
8065 stream->n_segments = 1;
8066 stream->dummy_segment = TRUE;
8068 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
8074 * Parses the stsd atom of a svq3 trak looking for
8075 * the SMI and gama atoms.
8078 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
8079 guint8 ** gamma, GstBuffer ** seqh)
8081 guint8 *_gamma = NULL;
8082 GstBuffer *_seqh = NULL;
8083 guint8 *stsd_data = stsd->data;
8084 guint32 length = QT_UINT32 (stsd_data);
8088 GST_WARNING_OBJECT (qtdemux, "stsd too short");
8094 version = QT_UINT16 (stsd_data);
8099 while (length > 8) {
8100 guint32 fourcc, size;
8102 size = QT_UINT32 (stsd_data);
8103 fourcc = QT_FOURCC (stsd_data + 4);
8104 data = stsd_data + 8;
8107 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
8108 "svq3 atom parsing");
8117 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
8118 " for gama atom, expected 12", size);
8123 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
8125 if (_seqh != NULL) {
8126 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
8127 " found, ignoring");
8129 seqh_size = QT_UINT32 (data + 4);
8130 if (seqh_size > 0) {
8131 _seqh = gst_buffer_new_and_alloc (seqh_size);
8132 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
8139 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
8140 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
8144 if (size <= length) {
8150 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
8153 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
8154 G_GUINT16_FORMAT, version);
8165 gst_buffer_unref (_seqh);
8170 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
8177 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
8178 * atom that might contain a 'data' atom with the rtsp uri.
8179 * This case was reported in bug #597497, some info about
8180 * the hndl atom can be found in TN1195
8182 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
8183 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
8186 guint32 dref_num_entries = 0;
8187 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
8188 gst_byte_reader_skip (&dref, 4) &&
8189 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
8192 /* search dref entries for hndl atom */
8193 for (i = 0; i < dref_num_entries; i++) {
8194 guint32 size = 0, type;
8195 guint8 string_len = 0;
8196 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
8197 qt_atom_parser_get_fourcc (&dref, &type)) {
8198 if (type == FOURCC_hndl) {
8199 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
8201 /* skip data reference handle bytes and the
8202 * following pascal string and some extra 4
8203 * bytes I have no idea what are */
8204 if (!gst_byte_reader_skip (&dref, 4) ||
8205 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
8206 !gst_byte_reader_skip (&dref, string_len + 4)) {
8207 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
8211 /* iterate over the atoms to find the data atom */
8212 while (gst_byte_reader_get_remaining (&dref) >= 8) {
8216 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
8217 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
8218 if (atom_type == FOURCC_data) {
8219 const guint8 *uri_aux = NULL;
8221 /* found the data atom that might contain the rtsp uri */
8222 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
8223 "hndl atom, interpreting it as an URI");
8224 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
8226 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
8227 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
8229 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
8230 "didn't contain a rtsp address");
8232 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
8237 /* skipping to the next entry */
8238 if (!gst_byte_reader_skip (&dref, atom_size - 8))
8241 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
8248 /* skip to the next entry */
8249 if (!gst_byte_reader_skip (&dref, size - 8))
8252 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
8255 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
8261 #define AMR_NB_ALL_MODES 0x81ff
8262 #define AMR_WB_ALL_MODES 0x83ff
8264 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
8266 /* The 'damr' atom is of the form:
8268 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
8269 * 32 b 8 b 16 b 8 b 8 b
8271 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
8272 * represents the highest mode used in the stream (and thus the maximum
8273 * bitrate), with a couple of special cases as seen below.
8276 /* Map of frame type ID -> bitrate */
8277 static const guint nb_bitrates[] = {
8278 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
8280 static const guint wb_bitrates[] = {
8281 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
8287 gst_buffer_map (buf, &map, GST_MAP_READ);
8289 if (map.size != 0x11) {
8290 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
8294 if (QT_FOURCC (map.data + 4) != GST_MAKE_FOURCC ('d', 'a', 'm', 'r')) {
8295 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
8296 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
8300 mode_set = QT_UINT16 (map.data + 13);
8302 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
8303 max_mode = 7 + (wb ? 1 : 0);
8305 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
8306 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
8308 if (max_mode == -1) {
8309 GST_DEBUG ("No mode indication was found (mode set) = %x",
8314 gst_buffer_unmap (buf, &map);
8315 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
8318 gst_buffer_unmap (buf, &map);
8323 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
8324 GstByteReader * reader, guint32 * matrix, const gchar * atom)
8327 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
8333 if (gst_byte_reader_get_remaining (reader) < 36)
8336 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
8337 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
8338 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
8339 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
8340 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
8341 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
8342 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
8343 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
8344 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
8346 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
8347 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
8348 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
8350 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
8351 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
8353 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
8354 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
8361 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
8362 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
8369 * This macro will only compare value abdegh, it expects cfi to have already
8372 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
8373 (m)[3] == (d << 16) && (m)[4] == (e << 16))
8375 /* only handle the cases where the last column has standard values */
8376 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
8377 const gchar *rotation_tag = NULL;
8379 /* no rotation needed */
8380 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
8382 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
8383 rotation_tag = "rotate-90";
8384 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
8385 rotation_tag = "rotate-180";
8386 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
8387 rotation_tag = "rotate-270";
8389 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
8392 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
8394 if (rotation_tag != NULL) {
8395 if (*taglist == NULL)
8396 *taglist = gst_tag_list_new_empty ();
8397 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
8398 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
8401 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
8405 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
8406 * protected streams (sinf, frma, schm and schi); if the protection scheme is
8407 * Common Encryption (cenc), the function will also parse the tenc box (defined
8408 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
8409 * (typically an enc[v|a|t|s] sample entry); the function will set
8410 * @original_fmt to the fourcc of the original unencrypted stream format.
8411 * Returns TRUE if successful; FALSE otherwise. */
8413 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
8414 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
8421 g_return_val_if_fail (qtdemux != NULL, FALSE);
8422 g_return_val_if_fail (stream != NULL, FALSE);
8423 g_return_val_if_fail (container != NULL, FALSE);
8424 g_return_val_if_fail (original_fmt != NULL, FALSE);
8426 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
8427 if (G_UNLIKELY (!sinf)) {
8428 if (stream->protection_scheme_type == FOURCC_cenc) {
8429 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
8430 "mandatory for Common Encryption");
8436 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
8437 if (G_UNLIKELY (!frma)) {
8438 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
8442 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
8443 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
8444 GST_FOURCC_ARGS (*original_fmt));
8446 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
8448 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
8451 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
8452 stream->protection_scheme_version =
8453 QT_UINT32 ((const guint8 *) schm->data + 16);
8455 GST_DEBUG_OBJECT (qtdemux,
8456 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
8457 "protection_scheme_version: %#010x",
8458 GST_FOURCC_ARGS (stream->protection_scheme_type),
8459 stream->protection_scheme_version);
8461 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
8463 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
8466 if (stream->protection_scheme_type == FOURCC_cenc) {
8467 QtDemuxCencSampleSetInfo *info;
8469 const guint8 *tenc_data;
8470 guint32 isEncrypted;
8472 const guint8 *default_kid;
8475 if (G_UNLIKELY (!stream->protection_scheme_info))
8476 stream->protection_scheme_info =
8477 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
8479 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
8481 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
8483 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
8484 "which is mandatory for Common Encryption");
8487 tenc_data = (const guint8 *) tenc->data + 12;
8488 isEncrypted = QT_UINT24 (tenc_data);
8489 iv_size = QT_UINT8 (tenc_data + 3);
8490 default_kid = (tenc_data + 4);
8491 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
8492 gst_buffer_fill (kid_buf, 0, default_kid, 16);
8493 if (info->default_properties)
8494 gst_structure_free (info->default_properties);
8495 info->default_properties =
8496 gst_structure_new ("application/x-cenc",
8497 "iv_size", G_TYPE_UINT, iv_size,
8498 "encrypted", G_TYPE_BOOLEAN, (isEncrypted == 1),
8499 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
8500 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
8501 "is_encrypted=%u, iv_size=%u", isEncrypted, iv_size);
8502 gst_buffer_unref (kid_buf);
8508 * With each track we associate a new QtDemuxStream that contains all the info
8510 * traks that do not decode to something (like strm traks) will not have a pad.
8513 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
8532 QtDemuxStream *stream = NULL;
8533 gboolean new_stream = FALSE;
8534 gchar *codec = NULL;
8535 const guint8 *stsd_data;
8536 guint16 lang_code; /* quicktime lang code or packed iso code */
8538 guint32 tkhd_flags = 0;
8539 guint8 tkhd_version = 0;
8541 guint value_size, stsd_len, len;
8545 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
8547 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
8548 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
8549 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
8552 /* pick between 64 or 32 bits */
8553 value_size = tkhd_version == 1 ? 8 : 4;
8554 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
8555 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
8558 if (!qtdemux->got_moov) {
8559 if (qtdemux_find_stream (qtdemux, track_id))
8560 goto existing_stream;
8561 stream = _create_stream ();
8562 stream->track_id = track_id;
8565 stream = qtdemux_find_stream (qtdemux, track_id);
8567 GST_WARNING_OBJECT (qtdemux, "Stream not found, going to ignore it");
8571 /* flush samples data from this track from previous moov */
8572 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
8573 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
8575 /* need defaults for fragments */
8576 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
8578 if (stream->pending_tags == NULL)
8579 stream->pending_tags = gst_tag_list_new_empty ();
8581 if ((tkhd_flags & 1) == 0)
8582 stream->disabled = TRUE;
8584 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
8585 tkhd_version, tkhd_flags, stream->track_id);
8587 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
8590 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
8591 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
8592 if (qtdemux->major_brand != FOURCC_mjp2 ||
8593 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
8597 len = QT_UINT32 ((guint8 *) mdhd->data);
8598 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
8599 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
8600 if (version == 0x01000000) {
8603 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
8604 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
8605 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
8609 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
8610 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
8611 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
8614 if (lang_code < 0x400) {
8615 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
8616 } else if (lang_code == 0x7fff) {
8617 stream->lang_id[0] = 0; /* unspecified */
8619 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
8620 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
8621 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
8622 stream->lang_id[3] = 0;
8625 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
8627 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
8629 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
8630 lang_code, stream->lang_id);
8632 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
8635 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
8636 /* chapters track reference */
8637 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
8639 gsize length = GST_READ_UINT32_BE (chap->data);
8640 if (qtdemux->chapters_track_id)
8641 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
8644 qtdemux->chapters_track_id =
8645 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
8650 /* fragmented files may have bogus duration in moov */
8651 if (!qtdemux->fragmented &&
8652 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
8653 guint64 tdur1, tdur2;
8655 /* don't overflow */
8656 tdur1 = stream->timescale * (guint64) qtdemux->duration;
8657 tdur2 = qtdemux->timescale * (guint64) stream->duration;
8660 * some of those trailers, nowadays, have prologue images that are
8661 * themselves vide tracks as well. I haven't really found a way to
8662 * identify those yet, except for just looking at their duration. */
8663 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
8664 GST_WARNING_OBJECT (qtdemux,
8665 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
8666 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
8667 "found, assuming preview image or something; skipping track",
8668 stream->duration, stream->timescale, qtdemux->duration,
8669 qtdemux->timescale);
8671 gst_qtdemux_stream_free (qtdemux, stream);
8676 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
8679 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
8680 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
8682 len = QT_UINT32 ((guint8 *) hdlr->data);
8684 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
8685 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
8686 GST_FOURCC_ARGS (stream->subtype));
8688 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
8691 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
8694 /*parse svmi header if existing */
8695 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
8697 len = QT_UINT32 ((guint8 *) svmi->data);
8698 version = QT_UINT32 ((guint8 *) svmi->data + 8);
8700 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
8701 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
8702 guint8 frame_type, frame_layout;
8704 /* MPEG-A stereo video */
8705 if (qtdemux->major_brand == FOURCC_ss02)
8706 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
8708 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
8709 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
8710 switch (frame_type) {
8712 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
8715 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
8718 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
8721 /* mode 3 is primary/secondary view sequence, ie
8722 * left/right views in separate tracks. See section 7.2
8723 * of ISO/IEC 23000-11:2009 */
8724 GST_FIXME_OBJECT (qtdemux,
8725 "Implement stereo video in separate streams");
8728 if ((frame_layout & 0x1) == 0)
8729 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
8731 GST_LOG_OBJECT (qtdemux,
8732 "StereoVideo: composition type: %u, is_left_first: %u",
8733 frame_type, frame_layout);
8734 stream->multiview_mode = mode;
8735 stream->multiview_flags = flags;
8740 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
8742 stsd_data = (const guint8 *) stsd->data;
8744 /* stsd should at least have one entry */
8745 stsd_len = QT_UINT32 (stsd_data);
8746 if (stsd_len < 24) {
8747 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
8748 if (stream->subtype == FOURCC_vivo) {
8750 gst_qtdemux_stream_free (qtdemux, stream);
8757 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
8759 /* and that entry should fit within stsd */
8760 len = QT_UINT32 (stsd_data + 16);
8761 if (len > stsd_len + 16)
8764 stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
8765 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
8766 GST_FOURCC_ARGS (stream->fourcc));
8767 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
8769 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
8770 goto error_encrypted;
8772 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
8773 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
8774 stream->protected = TRUE;
8775 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
8776 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
8779 if (stream->subtype == FOURCC_vide) {
8780 guint32 w = 0, h = 0;
8782 gint depth, palette_size, palette_count;
8784 guint32 *palette_data = NULL;
8786 stream->sampled = TRUE;
8788 /* version 1 uses some 64-bit ints */
8789 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
8792 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
8795 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
8796 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
8799 stream->display_width = w >> 16;
8800 stream->display_height = h >> 16;
8802 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
8803 &stream->pending_tags);
8809 stream->width = QT_UINT16 (stsd_data + offset + 32);
8810 stream->height = QT_UINT16 (stsd_data + offset + 34);
8811 stream->fps_n = 0; /* this is filled in later */
8812 stream->fps_d = 0; /* this is filled in later */
8813 stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
8814 stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
8816 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
8817 stream->width, stream->height, stream->bits_per_sample,
8818 stream->color_table_id);
8820 depth = stream->bits_per_sample;
8822 /* more than 32 bits means grayscale */
8823 gray = (depth > 32);
8824 /* low 32 bits specify the depth */
8827 /* different number of palette entries is determined by depth. */
8829 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
8830 palette_count = (1 << depth);
8831 palette_size = palette_count * 4;
8833 if (stream->color_table_id) {
8834 switch (palette_count) {
8838 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
8841 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
8845 palette_data = g_memdup (ff_qt_grayscale_palette_16, palette_size);
8847 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
8851 palette_data = g_memdup (ff_qt_grayscale_palette_256, palette_size);
8853 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
8856 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
8857 (_("The video in this file might not play correctly.")),
8858 ("unsupported palette depth %d", depth));
8862 gint i, j, start, end;
8868 start = QT_UINT32 (stsd_data + offset + 86);
8869 palette_count = QT_UINT16 (stsd_data + offset + 90);
8870 end = QT_UINT16 (stsd_data + offset + 92);
8872 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
8873 start, end, palette_count);
8880 if (len < 94 + (end - start) * 8)
8883 /* palette is always the same size */
8884 palette_data = g_malloc0 (256 * 4);
8885 palette_size = 256 * 4;
8887 for (j = 0, i = start; i <= end; j++, i++) {
8890 a = QT_UINT16 (stsd_data + offset + 94 + (j * 8));
8891 r = QT_UINT16 (stsd_data + offset + 96 + (j * 8));
8892 g = QT_UINT16 (stsd_data + offset + 98 + (j * 8));
8893 b = QT_UINT16 (stsd_data + offset + 100 + (j * 8));
8895 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
8896 (g & 0xff00) | (b >> 8);
8901 gst_caps_unref (stream->caps);
8904 qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
8905 if (G_UNLIKELY (!stream->caps)) {
8906 g_free (palette_data);
8907 goto unknown_stream;
8911 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
8912 GST_TAG_VIDEO_CODEC, codec, NULL);
8921 if (stream->rgb8_palette)
8922 gst_memory_unref (stream->rgb8_palette);
8923 stream->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
8924 palette_data, palette_size, 0, palette_size, palette_data, g_free);
8926 s = gst_caps_get_structure (stream->caps, 0);
8928 /* non-raw video has a palette_data property. raw video has the palette as
8929 * an extra plane that we append to the output buffers before we push
8931 if (!gst_structure_has_name (s, "video/x-raw")) {
8934 palette = gst_buffer_new ();
8935 gst_buffer_append_memory (palette, stream->rgb8_palette);
8936 stream->rgb8_palette = NULL;
8938 gst_caps_set_simple (stream->caps, "palette_data",
8939 GST_TYPE_BUFFER, palette, NULL);
8940 gst_buffer_unref (palette);
8942 } else if (palette_count != 0) {
8943 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
8944 (NULL), ("Unsupported palette depth %d", depth));
8947 GST_LOG_OBJECT (qtdemux, "frame count: %u",
8948 QT_UINT16 (stsd_data + offset + 48));
8952 /* pick 'the' stsd child */
8953 if (!stream->protected)
8954 mp4v = qtdemux_tree_get_child_by_type (stsd, fourcc);
8956 mp4v = qtdemux_tree_get_child_by_type (stsd, FOURCC_encv);
8959 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
8960 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
8964 const guint8 *pasp_data = (const guint8 *) pasp->data;
8966 stream->par_w = QT_UINT32 (pasp_data + 8);
8967 stream->par_h = QT_UINT32 (pasp_data + 12);
8974 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
8981 gint len = QT_UINT32 (stsd_data) - 0x66;
8982 const guint8 *avc_data = stsd_data + 0x66;
8985 while (len >= 0x8) {
8988 if (QT_UINT32 (avc_data) <= len)
8989 size = QT_UINT32 (avc_data) - 0x8;
8994 /* No real data, so break out */
8997 switch (QT_FOURCC (avc_data + 0x4)) {
9000 /* parse, if found */
9003 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
9005 /* First 4 bytes are the length of the atom, the next 4 bytes
9006 * are the fourcc, the next 1 byte is the version, and the
9007 * subsequent bytes are profile_tier_level structure like data. */
9008 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
9009 avc_data + 8 + 1, size - 1);
9010 buf = gst_buffer_new_and_alloc (size);
9011 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
9012 gst_caps_set_simple (stream->caps,
9013 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9014 gst_buffer_unref (buf);
9022 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
9024 /* First 4 bytes are the length of the atom, the next 4 bytes
9025 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
9026 * next 1 byte is the version, and the
9027 * subsequent bytes are sequence parameter set like data. */
9029 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
9031 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
9032 avc_data + 8 + 40 + 1, size - 1);
9034 buf = gst_buffer_new_and_alloc (size);
9035 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
9036 gst_caps_set_simple (stream->caps,
9037 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9038 gst_buffer_unref (buf);
9044 guint avg_bitrate, max_bitrate;
9046 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
9050 max_bitrate = QT_UINT32 (avc_data + 0xc);
9051 avg_bitrate = QT_UINT32 (avc_data + 0x10);
9053 if (!max_bitrate && !avg_bitrate)
9056 /* Some muxers seem to swap the average and maximum bitrates
9057 * (I'm looking at you, YouTube), so we swap for sanity. */
9058 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
9059 guint temp = avg_bitrate;
9061 avg_bitrate = max_bitrate;
9065 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
9066 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9067 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
9069 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
9070 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9071 GST_TAG_BITRATE, avg_bitrate, NULL);
9082 avc_data += size + 8;
9091 gint len = QT_UINT32 (stsd_data) - 0x66;
9092 const guint8 *hevc_data = stsd_data + 0x66;
9095 while (len >= 0x8) {
9098 if (QT_UINT32 (hevc_data) <= len)
9099 size = QT_UINT32 (hevc_data) - 0x8;
9104 /* No real data, so break out */
9107 switch (QT_FOURCC (hevc_data + 0x4)) {
9110 /* parse, if found */
9113 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
9115 /* First 4 bytes are the length of the atom, the next 4 bytes
9116 * are the fourcc, the next 1 byte is the version, and the
9117 * subsequent bytes are sequence parameter set like data. */
9118 gst_codec_utils_h265_caps_set_level_tier_and_profile
9119 (stream->caps, hevc_data + 8 + 1, size - 1);
9121 buf = gst_buffer_new_and_alloc (size);
9122 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
9123 gst_caps_set_simple (stream->caps,
9124 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9125 gst_buffer_unref (buf);
9132 hevc_data += size + 8;
9143 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
9144 GST_FOURCC_ARGS (fourcc));
9146 /* codec data might be in glbl extension atom */
9148 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
9154 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
9156 len = QT_UINT32 (data);
9159 buf = gst_buffer_new_and_alloc (len);
9160 gst_buffer_fill (buf, 0, data + 8, len);
9161 gst_caps_set_simple (stream->caps,
9162 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9163 gst_buffer_unref (buf);
9170 /* see annex I of the jpeg2000 spec */
9171 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
9173 const gchar *colorspace = NULL;
9175 guint32 ncomp_map = 0;
9176 gint32 *comp_map = NULL;
9177 guint32 nchan_def = 0;
9178 gint32 *chan_def = NULL;
9180 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
9181 /* some required atoms */
9182 mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
9185 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
9189 /* number of components; redundant with info in codestream, but useful
9191 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
9192 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
9194 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
9196 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
9199 GST_DEBUG_OBJECT (qtdemux, "found colr");
9200 /* extract colour space info */
9201 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
9202 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
9204 colorspace = "sRGB";
9207 colorspace = "GRAY";
9210 colorspace = "sYUV";
9218 /* colr is required, and only values 16, 17, and 18 are specified,
9219 so error if we have no colorspace */
9222 /* extract component mapping */
9223 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
9225 guint32 cmap_len = 0;
9227 cmap_len = QT_UINT32 (cmap->data);
9228 if (cmap_len >= 8) {
9229 /* normal box, subtract off header */
9231 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
9232 if (cmap_len % 4 == 0) {
9233 ncomp_map = (cmap_len / 4);
9234 comp_map = g_new0 (gint32, ncomp_map);
9235 for (i = 0; i < ncomp_map; i++) {
9238 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
9239 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
9240 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
9241 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
9246 /* extract channel definitions */
9247 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
9249 guint32 cdef_len = 0;
9251 cdef_len = QT_UINT32 (cdef->data);
9252 if (cdef_len >= 10) {
9253 /* normal box, subtract off header and len */
9255 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
9256 if (cdef_len % 6 == 0) {
9257 nchan_def = (cdef_len / 6);
9258 chan_def = g_new0 (gint32, nchan_def);
9259 for (i = 0; i < nchan_def; i++)
9261 for (i = 0; i < nchan_def; i++) {
9262 guint16 cn, typ, asoc;
9263 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
9264 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
9265 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
9266 if (cn < nchan_def) {
9269 chan_def[cn] = asoc;
9272 chan_def[cn] = 0; /* alpha */
9275 chan_def[cn] = -typ;
9283 gst_caps_set_simple (stream->caps,
9284 "num-components", G_TYPE_INT, ncomp, NULL);
9285 gst_caps_set_simple (stream->caps,
9286 "colorspace", G_TYPE_STRING, colorspace, NULL);
9289 GValue arr = { 0, };
9290 GValue elt = { 0, };
9292 g_value_init (&arr, GST_TYPE_ARRAY);
9293 g_value_init (&elt, G_TYPE_INT);
9294 for (i = 0; i < ncomp_map; i++) {
9295 g_value_set_int (&elt, comp_map[i]);
9296 gst_value_array_append_value (&arr, &elt);
9298 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
9299 "component-map", &arr);
9300 g_value_unset (&elt);
9301 g_value_unset (&arr);
9306 GValue arr = { 0, };
9307 GValue elt = { 0, };
9309 g_value_init (&arr, GST_TYPE_ARRAY);
9310 g_value_init (&elt, G_TYPE_INT);
9311 for (i = 0; i < nchan_def; i++) {
9312 g_value_set_int (&elt, chan_def[i]);
9313 gst_value_array_append_value (&arr, &elt);
9315 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
9316 "channel-definitions", &arr);
9317 g_value_unset (&elt);
9318 g_value_unset (&arr);
9322 /* some optional atoms */
9323 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
9324 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
9326 /* indicate possible fields in caps */
9328 data = (guint8 *) field->data + 8;
9330 gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
9331 (gint) * data, NULL);
9333 /* add codec_data if provided */
9338 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
9339 data = prefix->data;
9340 len = QT_UINT32 (data);
9343 buf = gst_buffer_new_and_alloc (len);
9344 gst_buffer_fill (buf, 0, data + 8, len);
9345 gst_caps_set_simple (stream->caps,
9346 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9347 gst_buffer_unref (buf);
9356 GstBuffer *seqh = NULL;
9357 guint8 *gamma_data = NULL;
9358 gint len = QT_UINT32 (stsd_data);
9360 qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
9362 gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
9363 QT_FP32 (gamma_data), NULL);
9366 /* sorry for the bad name, but we don't know what this is, other
9367 * than its own fourcc */
9368 gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
9372 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
9373 buf = gst_buffer_new_and_alloc (len);
9374 gst_buffer_fill (buf, 0, stsd_data, len);
9375 gst_caps_set_simple (stream->caps,
9376 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9377 gst_buffer_unref (buf);
9383 gst_caps_set_simple (stream->caps,
9384 "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
9391 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
9392 xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
9396 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
9400 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
9401 /* collect the headers and store them in a stream list so that we can
9402 * send them out first */
9403 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
9413 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
9414 ovc1 = qtdemux_tree_get_child_by_type (stsd, FOURCC_ovc1);
9417 ovc1_data = ovc1->data;
9418 ovc1_len = QT_UINT32 (ovc1_data);
9419 if (ovc1_len <= 198) {
9420 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
9423 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
9424 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
9425 gst_caps_set_simple (stream->caps,
9426 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9427 gst_buffer_unref (buf);
9430 case GST_MAKE_FOURCC ('v', 'c', '-', '1'):
9432 gint len = QT_UINT32 (stsd_data) - 0x66;
9433 const guint8 *vc1_data = stsd_data + 0x66;
9439 if (QT_UINT32 (vc1_data) <= len)
9440 size = QT_UINT32 (vc1_data) - 8;
9445 /* No real data, so break out */
9448 switch (QT_FOURCC (vc1_data + 0x4)) {
9449 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
9453 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
9454 buf = gst_buffer_new_and_alloc (size);
9455 gst_buffer_fill (buf, 0, vc1_data + 8, size);
9456 gst_caps_set_simple (stream->caps,
9457 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9458 gst_buffer_unref (buf);
9465 vc1_data += size + 8;
9474 GST_INFO_OBJECT (qtdemux,
9475 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
9476 GST_FOURCC_ARGS (fourcc), stream->caps);
9478 } else if (stream->subtype == FOURCC_soun) {
9479 int version, samplesize;
9480 guint16 compression_id;
9481 gboolean amrwb = FALSE;
9484 /* sample description entry (16) + sound sample description v0 (20) */
9488 version = QT_UINT32 (stsd_data + offset);
9489 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
9490 samplesize = QT_UINT16 (stsd_data + offset + 10);
9491 compression_id = QT_UINT16 (stsd_data + offset + 12);
9492 stream->rate = QT_FP32 (stsd_data + offset + 16);
9494 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
9495 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
9496 QT_UINT32 (stsd_data + offset + 4));
9497 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
9498 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
9499 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
9500 GST_LOG_OBJECT (qtdemux, "packet size: %d",
9501 QT_UINT16 (stsd_data + offset + 14));
9502 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
9504 if (compression_id == 0xfffe)
9505 stream->sampled = TRUE;
9507 /* first assume uncompressed audio */
9508 stream->bytes_per_sample = samplesize / 8;
9509 stream->samples_per_frame = stream->n_channels;
9510 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
9511 stream->samples_per_packet = stream->samples_per_frame;
9512 stream->bytes_per_packet = stream->bytes_per_sample;
9516 /* Yes, these have to be hard-coded */
9519 stream->samples_per_packet = 6;
9520 stream->bytes_per_packet = 1;
9521 stream->bytes_per_frame = 1 * stream->n_channels;
9522 stream->bytes_per_sample = 1;
9523 stream->samples_per_frame = 6 * stream->n_channels;
9528 stream->samples_per_packet = 3;
9529 stream->bytes_per_packet = 1;
9530 stream->bytes_per_frame = 1 * stream->n_channels;
9531 stream->bytes_per_sample = 1;
9532 stream->samples_per_frame = 3 * stream->n_channels;
9537 stream->samples_per_packet = 64;
9538 stream->bytes_per_packet = 34;
9539 stream->bytes_per_frame = 34 * stream->n_channels;
9540 stream->bytes_per_sample = 2;
9541 stream->samples_per_frame = 64 * stream->n_channels;
9547 stream->samples_per_packet = 1;
9548 stream->bytes_per_packet = 1;
9549 stream->bytes_per_frame = 1 * stream->n_channels;
9550 stream->bytes_per_sample = 1;
9551 stream->samples_per_frame = 1 * stream->n_channels;
9556 stream->samples_per_packet = 160;
9557 stream->bytes_per_packet = 33;
9558 stream->bytes_per_frame = 33 * stream->n_channels;
9559 stream->bytes_per_sample = 2;
9560 stream->samples_per_frame = 160 * stream->n_channels;
9567 if (version == 0x00010000) {
9568 /* sample description entry (16) + sound sample description v1 (20+16) */
9579 /* only parse extra decoding config for non-pcm audio */
9580 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
9581 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
9582 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
9583 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
9585 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
9586 stream->samples_per_packet);
9587 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
9588 stream->bytes_per_packet);
9589 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
9590 stream->bytes_per_frame);
9591 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
9592 stream->bytes_per_sample);
9594 if (!stream->sampled && stream->bytes_per_packet) {
9595 stream->samples_per_frame = (stream->bytes_per_frame /
9596 stream->bytes_per_packet) * stream->samples_per_packet;
9597 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
9598 stream->samples_per_frame);
9603 } else if (version == 0x00020000) {
9610 /* sample description entry (16) + sound sample description v2 (56) */
9614 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
9615 stream->rate = qtfp.fp;
9616 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
9618 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
9619 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
9620 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
9621 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
9622 QT_UINT32 (stsd_data + offset + 20));
9623 GST_LOG_OBJECT (qtdemux, "format flags: %X",
9624 QT_UINT32 (stsd_data + offset + 24));
9625 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
9626 QT_UINT32 (stsd_data + offset + 28));
9627 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
9628 QT_UINT32 (stsd_data + offset + 32));
9629 } else if (version != 0x00000) {
9630 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x", version);
9634 gst_caps_unref (stream->caps);
9636 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc,
9637 stsd_data + 32, len - 16, &codec);
9645 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
9647 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
9649 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
9651 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
9654 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
9655 gst_caps_set_simple (stream->caps,
9656 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE", NULL);
9663 const guint8 *owma_data;
9664 const gchar *codec_name = NULL;
9668 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
9669 /* FIXME this should also be gst_riff_strf_auds,
9670 * but the latter one is actually missing bits-per-sample :( */
9675 gint32 nSamplesPerSec;
9676 gint32 nAvgBytesPerSec;
9678 gint16 wBitsPerSample;
9683 GST_DEBUG_OBJECT (qtdemux, "parse owma");
9684 owma = qtdemux_tree_get_child_by_type (stsd, FOURCC_owma);
9687 owma_data = owma->data;
9688 owma_len = QT_UINT32 (owma_data);
9689 if (owma_len <= 54) {
9690 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
9693 wfex = (WAVEFORMATEX *) (owma_data + 36);
9694 buf = gst_buffer_new_and_alloc (owma_len - 54);
9695 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
9696 if (wfex->wFormatTag == 0x0161) {
9697 codec_name = "Windows Media Audio";
9699 } else if (wfex->wFormatTag == 0x0162) {
9700 codec_name = "Windows Media Audio 9 Pro";
9702 } else if (wfex->wFormatTag == 0x0163) {
9703 codec_name = "Windows Media Audio 9 Lossless";
9704 /* is that correct? gstffmpegcodecmap.c is missing it, but
9705 * fluendo codec seems to support it */
9709 gst_caps_set_simple (stream->caps,
9710 "codec_data", GST_TYPE_BUFFER, buf,
9711 "wmaversion", G_TYPE_INT, version,
9712 "block_align", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->nBlockAlign),
9713 "bitrate", G_TYPE_INT, GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec),
9714 "width", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
9715 "depth", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
9717 gst_buffer_unref (buf);
9721 codec = g_strdup (codec_name);
9725 case GST_MAKE_FOURCC ('w', 'm', 'a', ' '):
9727 gint len = QT_UINT32 (stsd_data) - offset;
9728 const guint8 *wfex_data = stsd_data + offset;
9729 const gchar *codec_name = NULL;
9731 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
9732 /* FIXME this should also be gst_riff_strf_auds,
9733 * but the latter one is actually missing bits-per-sample :( */
9738 gint32 nSamplesPerSec;
9739 gint32 nAvgBytesPerSec;
9741 gint16 wBitsPerSample;
9746 /* FIXME: unify with similar wavformatex parsing code above */
9747 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
9753 if (QT_UINT32 (wfex_data) <= len)
9754 size = QT_UINT32 (wfex_data) - 8;
9759 /* No real data, so break out */
9762 switch (QT_FOURCC (wfex_data + 4)) {
9763 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
9765 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
9770 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
9771 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
9772 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
9773 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
9774 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
9775 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
9776 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
9778 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
9779 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
9780 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
9781 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
9782 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
9783 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
9785 if (wfex.wFormatTag == 0x0161) {
9786 codec_name = "Windows Media Audio";
9788 } else if (wfex.wFormatTag == 0x0162) {
9789 codec_name = "Windows Media Audio 9 Pro";
9791 } else if (wfex.wFormatTag == 0x0163) {
9792 codec_name = "Windows Media Audio 9 Lossless";
9793 /* is that correct? gstffmpegcodecmap.c is missing it, but
9794 * fluendo codec seems to support it */
9798 gst_caps_set_simple (stream->caps,
9799 "wmaversion", G_TYPE_INT, version,
9800 "block_align", G_TYPE_INT, wfex.nBlockAlign,
9801 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
9802 "width", G_TYPE_INT, wfex.wBitsPerSample,
9803 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
9805 if (size > wfex.cbSize) {
9808 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
9809 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
9810 size - wfex.cbSize);
9811 gst_caps_set_simple (stream->caps,
9812 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9813 gst_buffer_unref (buf);
9815 GST_WARNING_OBJECT (qtdemux, "no codec data");
9820 codec = g_strdup (codec_name);
9828 wfex_data += size + 8;
9840 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9841 GST_TAG_AUDIO_CODEC, codec, NULL);
9845 /* some bitrate info may have ended up in caps */
9846 s = gst_caps_get_structure (stream->caps, 0);
9847 gst_structure_get_int (s, "bitrate", &bitrate);
9849 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9850 GST_TAG_BITRATE, bitrate, NULL);
9853 if (stream->protected && fourcc == FOURCC_mp4a)
9854 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_enca);
9856 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
9861 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
9863 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
9865 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
9869 /* If the fourcc's bottom 16 bits gives 'sm', then the top
9870 16 bits is a byte-swapped wave-style codec identifier,
9871 and we can find a WAVE header internally to a 'wave' atom here.
9872 This can more clearly be thought of as 'ms' as the top 16 bits, and a
9873 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
9876 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
9877 if (len < offset + 20) {
9878 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
9880 guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
9881 const guint8 *data = stsd_data + offset + 16;
9883 GNode *waveheadernode;
9885 wavenode = g_node_new ((guint8 *) data);
9886 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
9887 const guint8 *waveheader;
9890 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
9891 if (waveheadernode) {
9892 waveheader = (const guint8 *) waveheadernode->data;
9893 headerlen = QT_UINT32 (waveheader);
9895 if (headerlen > 8) {
9896 gst_riff_strf_auds *header = NULL;
9897 GstBuffer *headerbuf;
9903 headerbuf = gst_buffer_new_and_alloc (headerlen);
9904 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
9906 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
9907 headerbuf, &header, &extra)) {
9908 gst_caps_unref (stream->caps);
9909 /* FIXME: Need to do something with the channel reorder map */
9910 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
9911 header, extra, NULL, NULL, NULL);
9914 gst_buffer_unref (extra);
9919 GST_DEBUG ("Didn't find waveheadernode for this codec");
9921 g_node_destroy (wavenode);
9924 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
9928 /* FIXME: what is in the chunk? */
9931 gint len = QT_UINT32 (stsd_data);
9933 /* seems to be always = 116 = 0x74 */
9939 gint len = QT_UINT32 (stsd_data);
9942 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
9944 gst_buffer_fill (buf, 0, stsd_data + 0x4C, len - 0x4C);
9945 gst_caps_set_simple (stream->caps,
9946 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9947 gst_buffer_unref (buf);
9949 gst_caps_set_simple (stream->caps,
9950 "samplesize", G_TYPE_INT, samplesize, NULL);
9955 GNode *alac, *wave = NULL;
9957 /* apparently, m4a has this atom appended directly in the stsd entry,
9958 * while mov has it in a wave atom */
9959 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
9961 /* alac now refers to stsd entry atom */
9962 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
9964 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
9966 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
9969 const guint8 *alac_data = alac->data;
9970 gint len = QT_UINT32 (alac->data);
9974 GST_DEBUG_OBJECT (qtdemux,
9975 "discarding alac atom with unexpected len %d", len);
9977 /* codec-data contains alac atom size and prefix,
9978 * ffmpeg likes it that way, not quite gst-ish though ...*/
9979 buf = gst_buffer_new_and_alloc (len);
9980 gst_buffer_fill (buf, 0, alac->data, len);
9981 gst_caps_set_simple (stream->caps,
9982 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9983 gst_buffer_unref (buf);
9985 stream->bytes_per_frame = QT_UINT32 (alac_data + 12);
9986 stream->n_channels = QT_UINT8 (alac_data + 21);
9987 stream->rate = QT_UINT32 (alac_data + 32);
9990 gst_caps_set_simple (stream->caps,
9991 "samplesize", G_TYPE_INT, samplesize, NULL);
9999 gint len = QT_UINT32 (stsd_data);
10002 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
10005 gst_buffer_fill (buf, 0, stsd_data + 0x34, len - 0x34);
10007 /* If we have enough data, let's try to get the 'damr' atom. See
10008 * the 3GPP container spec (26.244) for more details. */
10009 if ((len - 0x34) > 8 &&
10010 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
10011 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10012 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
10015 gst_caps_set_simple (stream->caps,
10016 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10017 gst_buffer_unref (buf);
10023 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
10024 gint len = QT_UINT32 (stsd_data);
10027 guint16 sound_version = QT_UINT16 (stsd_data + 32);
10029 if (sound_version == 1) {
10030 guint16 channels = QT_UINT16 (stsd_data + 40);
10031 guint32 time_scale = QT_UINT32 (stsd_data + 46);
10032 guint8 codec_data[2];
10034 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
10036 gint sample_rate_index =
10037 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
10039 /* build AAC codec data */
10040 codec_data[0] = profile << 3;
10041 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
10042 codec_data[1] = (sample_rate_index & 0x01) << 7;
10043 codec_data[1] |= (channels & 0xF) << 3;
10045 buf = gst_buffer_new_and_alloc (2);
10046 gst_buffer_fill (buf, 0, codec_data, 2);
10047 gst_caps_set_simple (stream->caps,
10048 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10049 gst_buffer_unref (buf);
10055 GST_INFO_OBJECT (qtdemux,
10056 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
10060 GST_INFO_OBJECT (qtdemux,
10061 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10062 GST_FOURCC_ARGS (fourcc), stream->caps);
10064 } else if (stream->subtype == FOURCC_strm) {
10065 if (fourcc == FOURCC_rtsp) {
10066 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
10068 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
10069 GST_FOURCC_ARGS (fourcc));
10070 goto unknown_stream;
10072 stream->sampled = TRUE;
10073 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
10074 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
10076 stream->sampled = TRUE;
10077 stream->sparse = TRUE;
10080 qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
10082 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10083 GST_TAG_SUBTITLE_CODEC, codec, NULL);
10088 /* hunt for sort-of codec data */
10092 GNode *mp4s = NULL;
10093 GNode *esds = NULL;
10095 /* look for palette in a stsd->mp4s->esds sub-atom */
10096 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
10098 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
10099 if (esds == NULL) {
10101 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
10105 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
10109 GST_INFO_OBJECT (qtdemux,
10110 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
10113 GST_INFO_OBJECT (qtdemux,
10114 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10115 GST_FOURCC_ARGS (fourcc), stream->caps);
10117 /* everything in 1 sample */
10118 stream->sampled = TRUE;
10121 qtdemux_generic_caps (qtdemux, stream, fourcc, stsd_data, &codec);
10123 if (stream->caps == NULL)
10124 goto unknown_stream;
10127 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10128 GST_TAG_SUBTITLE_CODEC, codec, NULL);
10134 /* promote to sampled format */
10135 if (stream->fourcc == FOURCC_samr) {
10136 /* force mono 8000 Hz for AMR */
10137 stream->sampled = TRUE;
10138 stream->n_channels = 1;
10139 stream->rate = 8000;
10140 } else if (stream->fourcc == FOURCC_sawb) {
10141 /* force mono 16000 Hz for AMR-WB */
10142 stream->sampled = TRUE;
10143 stream->n_channels = 1;
10144 stream->rate = 16000;
10145 } else if (stream->fourcc == FOURCC_mp4a) {
10146 stream->sampled = TRUE;
10149 /* collect sample information */
10150 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
10151 goto samples_failed;
10153 if (qtdemux->fragmented) {
10156 /* need all moov samples as basis; probably not many if any at all */
10157 /* prevent moof parsing taking of at this time */
10158 offset = qtdemux->moof_offset;
10159 qtdemux->moof_offset = 0;
10160 if (stream->n_samples &&
10161 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
10162 qtdemux->moof_offset = offset;
10163 goto samples_failed;
10165 qtdemux->moof_offset = 0;
10166 /* movie duration more reliable in this case (e.g. mehd) */
10167 if (qtdemux->segment.duration &&
10168 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
10170 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
10173 /* configure segments */
10174 if (!qtdemux_parse_segments (qtdemux, stream, trak))
10175 goto segments_failed;
10177 /* add some language tag, if useful */
10178 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
10179 strcmp (stream->lang_id, "und")) {
10180 const gchar *lang_code;
10182 /* convert ISO 639-2 code to ISO 639-1 */
10183 lang_code = gst_tag_get_language_code (stream->lang_id);
10184 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10185 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
10188 /* Check for UDTA tags */
10189 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
10190 qtdemux_parse_udta (qtdemux, stream->pending_tags, udta);
10193 /* now we are ready to add the stream */
10194 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
10195 goto too_many_streams;
10197 if (!qtdemux->got_moov) {
10198 qtdemux->streams[qtdemux->n_streams] = stream;
10199 qtdemux->n_streams++;
10200 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
10208 GST_INFO_OBJECT (qtdemux, "skip disabled track");
10210 gst_qtdemux_stream_free (qtdemux, stream);
10215 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10216 (_("This file is corrupt and cannot be played.")), (NULL));
10218 gst_qtdemux_stream_free (qtdemux, stream);
10223 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
10225 gst_qtdemux_stream_free (qtdemux, stream);
10231 /* we posted an error already */
10232 /* free stbl sub-atoms */
10233 gst_qtdemux_stbl_free (stream);
10235 gst_qtdemux_stream_free (qtdemux, stream);
10240 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
10243 gst_qtdemux_stream_free (qtdemux, stream);
10248 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
10249 GST_FOURCC_ARGS (stream->subtype));
10251 gst_qtdemux_stream_free (qtdemux, stream);
10256 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
10257 (_("This file contains too many streams. Only playing first %d"),
10258 GST_QTDEMUX_MAX_STREAMS), (NULL));
10263 /* If we can estimate the overall bitrate, and don't have information about the
10264 * stream bitrate for exactly one stream, this guesses the stream bitrate as
10265 * the overall bitrate minus the sum of the bitrates of all other streams. This
10266 * should be useful for the common case where we have one audio and one video
10267 * stream and can estimate the bitrate of one, but not the other. */
10269 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
10271 QtDemuxStream *stream = NULL;
10272 gint64 size, sys_bitrate, sum_bitrate = 0;
10273 GstClockTime duration;
10277 if (qtdemux->fragmented)
10280 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
10282 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
10284 GST_DEBUG_OBJECT (qtdemux,
10285 "Size in bytes of the stream not known - bailing");
10289 /* Subtract the header size */
10290 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
10291 size, qtdemux->header_size);
10293 if (size < qtdemux->header_size)
10296 size = size - qtdemux->header_size;
10298 if (!gst_qtdemux_get_duration (qtdemux, &duration) ||
10299 duration == GST_CLOCK_TIME_NONE) {
10300 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
10304 for (i = 0; i < qtdemux->n_streams; i++) {
10305 switch (qtdemux->streams[i]->subtype) {
10308 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
10309 qtdemux->streams[i]->caps);
10310 /* retrieve bitrate, prefer avg then max */
10312 if (qtdemux->streams[i]->pending_tags) {
10313 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
10314 GST_TAG_MAXIMUM_BITRATE, &bitrate);
10315 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
10316 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
10317 GST_TAG_NOMINAL_BITRATE, &bitrate);
10318 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
10319 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
10320 GST_TAG_BITRATE, &bitrate);
10321 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
10324 sum_bitrate += bitrate;
10327 GST_DEBUG_OBJECT (qtdemux,
10328 ">1 stream with unknown bitrate - bailing");
10331 stream = qtdemux->streams[i];
10335 /* For other subtypes, we assume no significant impact on bitrate */
10341 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
10345 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
10347 if (sys_bitrate < sum_bitrate) {
10348 /* This can happen, since sum_bitrate might be derived from maximum
10349 * bitrates and not average bitrates */
10350 GST_DEBUG_OBJECT (qtdemux,
10351 "System bitrate less than sum bitrate - bailing");
10355 bitrate = sys_bitrate - sum_bitrate;
10356 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
10357 ", Stream bitrate = %u", sys_bitrate, bitrate);
10359 if (!stream->pending_tags)
10360 stream->pending_tags = gst_tag_list_new_empty ();
10362 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10363 GST_TAG_BITRATE, bitrate, NULL);
10366 static GstFlowReturn
10367 qtdemux_prepare_streams (GstQTDemux * qtdemux)
10370 GstFlowReturn ret = GST_FLOW_OK;
10372 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
10374 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
10375 QtDemuxStream *stream = qtdemux->streams[i];
10376 guint32 sample_num = 0;
10378 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
10379 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
10381 if (qtdemux->fragmented) {
10382 /* need all moov samples first */
10383 GST_OBJECT_LOCK (qtdemux);
10384 while (stream->n_samples == 0)
10385 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
10387 GST_OBJECT_UNLOCK (qtdemux);
10389 /* discard any stray moof */
10390 qtdemux->moof_offset = 0;
10393 /* prepare braking */
10394 if (ret != GST_FLOW_ERROR)
10397 /* in pull mode, we should have parsed some sample info by now;
10398 * and quite some code will not handle no samples.
10399 * in push mode, we'll just have to deal with it */
10400 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
10401 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
10402 gst_qtdemux_remove_stream (qtdemux, i);
10407 /* parse the initial sample for use in setting the frame rate cap */
10408 while (sample_num == 0 && sample_num < stream->n_samples) {
10409 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
10413 if (stream->n_samples > 0 && stream->stbl_index >= 0) {
10414 stream->first_duration = stream->samples[0].duration;
10415 GST_LOG_OBJECT (qtdemux, "stream %d first duration %u",
10416 stream->track_id, stream->first_duration);
10423 static GstFlowReturn
10424 qtdemux_expose_streams (GstQTDemux * qtdemux)
10427 GstFlowReturn ret = GST_FLOW_OK;
10428 GSList *oldpads = NULL;
10431 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
10433 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
10434 QtDemuxStream *stream = qtdemux->streams[i];
10435 GstPad *oldpad = stream->pad;
10438 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
10439 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
10441 if ((stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl) &&
10442 stream->track_id == qtdemux->chapters_track_id) {
10443 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
10444 so that it doesn't look like a subtitle track */
10445 gst_qtdemux_remove_stream (qtdemux, i);
10450 /* now we have all info and can expose */
10451 list = stream->pending_tags;
10452 stream->pending_tags = NULL;
10454 oldpads = g_slist_prepend (oldpads, oldpad);
10455 gst_qtdemux_add_stream (qtdemux, stream, list);
10458 gst_qtdemux_guess_bitrate (qtdemux);
10460 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
10462 for (iter = oldpads; iter; iter = g_slist_next (iter)) {
10463 GstPad *oldpad = iter->data;
10465 gst_pad_push_event (oldpad, gst_event_new_eos ());
10466 gst_pad_set_active (oldpad, FALSE);
10467 gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
10468 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, oldpad);
10469 gst_object_unref (oldpad);
10472 /* check if we should post a redirect in case there is a single trak
10473 * and it is a redirecting trak */
10474 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
10477 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
10478 "an external content");
10479 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
10480 gst_structure_new ("redirect",
10481 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
10483 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
10484 qtdemux->posted_redirect = TRUE;
10487 for (i = 0; i < qtdemux->n_streams; i++) {
10488 QtDemuxStream *stream = qtdemux->streams[i];
10490 qtdemux_do_allocation (qtdemux, stream);
10493 qtdemux->exposed = TRUE;
10497 /* check if major or compatible brand is 3GP */
10498 static inline gboolean
10499 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
10502 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
10503 GST_MAKE_FOURCC ('3', 'g', 0, 0));
10504 } else if (qtdemux->comp_brands != NULL) {
10508 gboolean res = FALSE;
10510 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
10513 while (size >= 4) {
10514 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
10515 GST_MAKE_FOURCC ('3', 'g', 0, 0));
10519 gst_buffer_unmap (qtdemux->comp_brands, &map);
10526 /* check if tag is a spec'ed 3GP tag keyword storing a string */
10527 static inline gboolean
10528 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
10530 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
10531 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
10532 || fourcc == FOURCC_albm;
10536 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
10537 const char *tag, const char *dummy, GNode * node)
10539 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
10543 gdouble longitude, latitude, altitude;
10546 len = QT_UINT32 (node->data);
10553 /* TODO: language code skipped */
10555 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
10558 /* do not alarm in trivial case, but bail out otherwise */
10559 if (*(data + offset) != 0) {
10560 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
10564 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
10565 GST_TAG_GEO_LOCATION_NAME, name, NULL);
10566 offset += strlen (name);
10570 if (len < offset + 2 + 4 + 4 + 4)
10573 /* +1 +1 = skip null-terminator and location role byte */
10575 /* table in spec says unsigned, semantics say negative has meaning ... */
10576 longitude = QT_SFP32 (data + offset);
10579 latitude = QT_SFP32 (data + offset);
10582 altitude = QT_SFP32 (data + offset);
10584 /* one invalid means all are invalid */
10585 if (longitude >= -180.0 && longitude <= 180.0 &&
10586 latitude >= -90.0 && latitude <= 90.0) {
10587 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
10588 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
10589 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
10590 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
10593 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
10600 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
10607 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
10608 const char *tag, const char *dummy, GNode * node)
10614 len = QT_UINT32 (node->data);
10618 y = QT_UINT16 ((guint8 *) node->data + 12);
10620 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
10623 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
10625 date = g_date_new_dmy (1, 1, y);
10626 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
10627 g_date_free (date);
10631 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
10632 const char *tag, const char *dummy, GNode * node)
10635 char *tag_str = NULL;
10640 len = QT_UINT32 (node->data);
10645 entity = (guint8 *) node->data + offset;
10646 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
10647 GST_DEBUG_OBJECT (qtdemux,
10648 "classification info: %c%c%c%c invalid classification entity",
10649 entity[0], entity[1], entity[2], entity[3]);
10654 table = QT_UINT16 ((guint8 *) node->data + offset);
10656 /* Language code skipped */
10660 /* Tag format: "XXXX://Y[YYYY]/classification info string"
10661 * XXXX: classification entity, fixed length 4 chars.
10662 * Y[YYYY]: classification table, max 5 chars.
10664 tag_str = g_strdup_printf ("----://%u/%s",
10665 table, (char *) node->data + offset);
10667 /* memcpy To be sure we're preserving byte order */
10668 memcpy (tag_str, entity, 4);
10669 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
10671 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
10680 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
10686 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
10687 const char *tag, const char *dummy, GNode * node)
10689 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
10695 gboolean ret = TRUE;
10696 const gchar *charset = NULL;
10698 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
10700 len = QT_UINT32 (data->data);
10701 type = QT_UINT32 ((guint8 *) data->data + 8);
10702 if (type == 0x00000001 && len > 16) {
10703 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
10706 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
10707 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
10710 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
10714 len = QT_UINT32 (node->data);
10715 type = QT_UINT32 ((guint8 *) node->data + 4);
10716 if ((type >> 24) == 0xa9) {
10720 /* Type starts with the (C) symbol, so the next data is a list
10721 * of (string size(16), language code(16), string) */
10723 str_len = QT_UINT16 ((guint8 *) node->data + 8);
10724 lang_code = QT_UINT16 ((guint8 *) node->data + 10);
10726 /* the string + fourcc + size + 2 16bit fields,
10727 * means that there are more tags in this atom */
10728 if (len > str_len + 8 + 4) {
10729 /* TODO how to represent the same tag in different languages? */
10730 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
10731 "text alternatives, reading only first one");
10735 len = str_len + 8 + 4; /* remove trailing strings that we don't use */
10736 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
10738 if (lang_code < 0x800) { /* MAC encoded string */
10741 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
10742 QT_FOURCC ((guint8 *) node->data + 4))) {
10743 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
10745 /* we go for 3GP style encoding if major brands claims so,
10746 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
10747 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
10748 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
10749 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
10751 /* 16-bit Language code is ignored here as well */
10752 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
10759 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
10760 ret = FALSE; /* may have to fallback */
10763 GError *err = NULL;
10765 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
10766 charset, NULL, NULL, &err);
10768 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
10769 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
10771 g_error_free (err);
10774 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
10775 len - offset, env_vars);
10778 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
10779 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
10783 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
10790 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
10791 const char *tag, const char *dummy, GNode * node)
10793 qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
10797 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
10798 const char *tag, const char *dummy, GNode * node)
10800 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
10802 char *s, *t, *k = NULL;
10807 /* first try normal string tag if major brand not 3GP */
10808 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
10809 if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
10810 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
10811 * let's try it 3gpp way after minor safety check */
10813 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
10819 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
10823 len = QT_UINT32 (data);
10827 count = QT_UINT8 (data + 14);
10829 for (; count; count--) {
10832 if (offset + 1 > len)
10834 slen = QT_UINT8 (data + offset);
10836 if (offset + slen > len)
10838 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
10841 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
10843 t = g_strjoin (",", k, s, NULL);
10851 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
10858 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
10859 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
10868 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
10874 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
10875 const char *tag1, const char *tag2, GNode * node)
10882 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
10884 len = QT_UINT32 (data->data);
10885 type = QT_UINT32 ((guint8 *) data->data + 8);
10886 if (type == 0x00000000 && len >= 22) {
10887 n1 = QT_UINT16 ((guint8 *) data->data + 18);
10888 n2 = QT_UINT16 ((guint8 *) data->data + 20);
10890 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
10891 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
10894 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
10895 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
10902 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
10903 const char *tag1, const char *dummy, GNode * node)
10910 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
10912 len = QT_UINT32 (data->data);
10913 type = QT_UINT32 ((guint8 *) data->data + 8);
10914 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
10915 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
10916 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
10917 n1 = QT_UINT16 ((guint8 *) data->data + 16);
10919 /* do not add bpm=0 */
10920 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
10921 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
10929 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
10930 const char *tag1, const char *dummy, GNode * node)
10937 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
10939 len = QT_UINT32 (data->data);
10940 type = QT_UINT32 ((guint8 *) data->data + 8);
10941 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
10942 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
10943 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
10944 num = QT_UINT32 ((guint8 *) data->data + 16);
10946 /* do not add num=0 */
10947 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
10948 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
10955 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
10956 const char *tag1, const char *dummy, GNode * node)
10963 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
10965 len = QT_UINT32 (data->data);
10966 type = QT_UINT32 ((guint8 *) data->data + 8);
10967 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
10968 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
10970 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
10971 len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
10972 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
10973 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
10974 gst_sample_unref (sample);
10981 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
10982 const char *tag, const char *dummy, GNode * node)
10989 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
10991 len = QT_UINT32 (data->data);
10992 type = QT_UINT32 ((guint8 *) data->data + 8);
10993 if (type == 0x00000001 && len > 16) {
10994 guint y, m = 1, d = 1;
10997 s = g_strndup ((char *) data->data + 16, len - 16);
10998 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
10999 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
11000 if (ret >= 1 && y > 1500 && y < 3000) {
11003 date = g_date_new_dmy (d, m, y);
11004 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
11005 g_date_free (date);
11007 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
11015 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
11016 const char *tag, const char *dummy, GNode * node)
11020 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11022 /* re-route to normal string tag if major brand says so
11023 * or no data atom and compatible brand suggests so */
11024 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
11025 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
11026 qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
11031 guint len, type, n;
11033 len = QT_UINT32 (data->data);
11034 type = QT_UINT32 ((guint8 *) data->data + 8);
11035 if (type == 0x00000000 && len >= 18) {
11036 n = QT_UINT16 ((guint8 *) data->data + 16);
11038 const gchar *genre;
11040 genre = gst_tag_id3_genre_get (n - 1);
11041 if (genre != NULL) {
11042 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
11043 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
11051 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
11052 const gchar * tag, guint8 * data, guint32 datasize)
11057 /* make a copy to have \0 at the end */
11058 datacopy = g_strndup ((gchar *) data, datasize);
11060 /* convert the str to double */
11061 if (sscanf (datacopy, "%lf", &value) == 1) {
11062 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
11063 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
11065 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
11073 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
11074 const char *tag, const char *tag_bis, GNode * node)
11083 const gchar *meanstr;
11084 const gchar *namestr;
11086 /* checking the whole ---- atom size for consistency */
11087 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
11088 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
11092 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
11094 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
11098 meansize = QT_UINT32 (mean->data);
11099 if (meansize <= 12) {
11100 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
11103 meanstr = ((gchar *) mean->data) + 12;
11106 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
11108 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
11112 namesize = QT_UINT32 (name->data);
11113 if (namesize <= 12) {
11114 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
11117 namestr = ((gchar *) name->data) + 12;
11125 * uint24 - data type
11129 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11131 GST_WARNING_OBJECT (demux, "No data atom in this tag");
11134 datasize = QT_UINT32 (data->data);
11135 if (datasize <= 16) {
11136 GST_WARNING_OBJECT (demux, "Data atom too small");
11139 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
11141 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
11142 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
11143 static const struct
11145 const gchar name[28];
11146 const gchar tag[28];
11149 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
11150 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
11151 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
11152 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
11153 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
11154 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
11155 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
11156 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
11160 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
11161 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
11162 switch (gst_tag_get_type (tags[i].tag)) {
11163 case G_TYPE_DOUBLE:
11164 qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
11165 ((guint8 *) data->data) + 16, datasize - 16);
11167 case G_TYPE_STRING:
11168 qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
11177 if (i == G_N_ELEMENTS (tags))
11187 #ifndef GST_DISABLE_GST_DEBUG
11189 gchar *namestr_dbg;
11190 gchar *meanstr_dbg;
11192 meanstr_dbg = g_strndup (meanstr, meansize);
11193 namestr_dbg = g_strndup (namestr, namesize);
11195 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
11196 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
11198 g_free (namestr_dbg);
11199 g_free (meanstr_dbg);
11206 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
11207 const char *tag_bis, GNode * node)
11212 GstTagList *id32_taglist = NULL;
11214 GST_LOG_OBJECT (demux, "parsing ID32");
11217 len = GST_READ_UINT32_BE (data);
11219 /* need at least full box and language tag */
11223 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
11224 gst_buffer_fill (buf, 0, data + 14, len - 14);
11226 id32_taglist = gst_tag_list_from_id3v2_tag (buf);
11227 if (id32_taglist) {
11228 GST_LOG_OBJECT (demux, "parsing ok");
11229 gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
11230 gst_tag_list_unref (id32_taglist);
11232 GST_LOG_OBJECT (demux, "parsing failed");
11235 gst_buffer_unref (buf);
11238 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
11239 const char *tag, const char *tag_bis, GNode * node);
11242 FOURCC_pcst -> if media is a podcast -> bool
11243 FOURCC_cpil -> if media is part of a compilation -> bool
11244 FOURCC_pgap -> if media is part of a gapless context -> bool
11245 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
11248 static const struct
11251 const gchar *gst_tag;
11252 const gchar *gst_tag_bis;
11253 const GstQTDemuxAddTagFunc func;
11256 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
11257 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
11258 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
11259 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
11260 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
11261 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
11262 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
11263 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
11264 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
11265 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
11266 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
11267 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
11268 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
11269 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
11270 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
11271 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
11272 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
11273 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
11274 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
11275 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
11276 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
11277 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
11278 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
11279 qtdemux_tag_add_num}, {
11280 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
11281 qtdemux_tag_add_num}, {
11282 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
11283 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
11284 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
11285 FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
11286 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
11287 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
11288 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
11289 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
11290 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
11291 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
11292 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
11293 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
11294 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
11295 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
11296 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
11297 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
11298 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
11299 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
11300 qtdemux_tag_add_classification}, {
11301 FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
11302 FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
11303 FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
11305 /* This is a special case, some tags are stored in this
11306 * 'reverse dns naming', according to:
11307 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
11310 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
11311 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
11312 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
11315 struct _GstQtDemuxTagList
11318 GstTagList *taglist;
11320 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
11323 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
11329 const gchar *style;
11334 GstQTDemux *demux = qtdemuxtaglist->demux;
11335 GstTagList *taglist = qtdemuxtaglist->taglist;
11338 len = QT_UINT32 (data);
11339 buf = gst_buffer_new_and_alloc (len);
11340 gst_buffer_fill (buf, 0, data, len);
11342 /* heuristic to determine style of tag */
11343 if (QT_FOURCC (data + 4) == FOURCC_____ ||
11344 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
11346 else if (demux->major_brand == FOURCC_qt__)
11347 style = "quicktime";
11348 /* fall back to assuming iso/3gp tag style */
11352 /* santize the name for the caps. */
11353 for (i = 0; i < 4; i++) {
11354 guint8 d = data[4 + i];
11355 if (g_ascii_isalnum (d))
11356 ndata[i] = g_ascii_tolower (d);
11361 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
11362 ndata[0], ndata[1], ndata[2], ndata[3]);
11363 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
11365 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
11366 sample = gst_sample_new (buf, NULL, NULL, s);
11367 gst_buffer_unref (buf);
11368 g_free (media_type);
11370 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
11373 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
11374 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
11376 gst_sample_unref (sample);
11380 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
11387 GstQtDemuxTagList demuxtaglist;
11389 demuxtaglist.demux = qtdemux;
11390 demuxtaglist.taglist = taglist;
11392 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
11393 if (meta != NULL) {
11394 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
11395 if (ilst == NULL) {
11396 GST_LOG_OBJECT (qtdemux, "no ilst");
11401 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
11405 while (i < G_N_ELEMENTS (add_funcs)) {
11406 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
11410 len = QT_UINT32 (node->data);
11412 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
11413 GST_FOURCC_ARGS (add_funcs[i].fourcc));
11415 add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
11416 add_funcs[i].gst_tag_bis, node);
11418 g_node_destroy (node);
11424 /* parsed nodes have been removed, pass along remainder as blob */
11425 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
11426 (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
11428 /* parse up XMP_ node if existing */
11429 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
11430 if (xmp_ != NULL) {
11432 GstTagList *xmptaglist;
11434 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
11435 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
11436 xmptaglist = gst_tag_list_from_xmp_buffer (buf);
11437 gst_buffer_unref (buf);
11439 qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
11441 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
11447 GstStructure *structure; /* helper for sort function */
11449 guint min_req_bitrate;
11450 guint min_req_qt_version;
11454 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
11456 GstQtReference *ref_a = (GstQtReference *) a;
11457 GstQtReference *ref_b = (GstQtReference *) b;
11459 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
11460 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
11462 /* known bitrates go before unknown; higher bitrates go first */
11463 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
11466 /* sort the redirects and post a message for the application.
11469 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
11471 GstQtReference *best;
11474 GValue list_val = { 0, };
11477 g_assert (references != NULL);
11479 references = g_list_sort (references, qtdemux_redirects_sort_func);
11481 best = (GstQtReference *) references->data;
11483 g_value_init (&list_val, GST_TYPE_LIST);
11485 for (l = references; l != NULL; l = l->next) {
11486 GstQtReference *ref = (GstQtReference *) l->data;
11487 GValue struct_val = { 0, };
11489 ref->structure = gst_structure_new ("redirect",
11490 "new-location", G_TYPE_STRING, ref->location, NULL);
11492 if (ref->min_req_bitrate > 0) {
11493 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
11494 ref->min_req_bitrate, NULL);
11497 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
11498 g_value_set_boxed (&struct_val, ref->structure);
11499 gst_value_list_append_value (&list_val, &struct_val);
11500 g_value_unset (&struct_val);
11501 /* don't free anything here yet, since we need best->structure below */
11504 g_assert (best != NULL);
11505 s = gst_structure_copy (best->structure);
11507 if (g_list_length (references) > 1) {
11508 gst_structure_set_value (s, "locations", &list_val);
11511 g_value_unset (&list_val);
11513 for (l = references; l != NULL; l = l->next) {
11514 GstQtReference *ref = (GstQtReference *) l->data;
11516 gst_structure_free (ref->structure);
11517 g_free (ref->location);
11520 g_list_free (references);
11522 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
11523 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
11524 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
11525 qtdemux->posted_redirect = TRUE;
11528 /* look for redirect nodes, collect all redirect information and
11532 qtdemux_parse_redirects (GstQTDemux * qtdemux)
11534 GNode *rmra, *rmda, *rdrf;
11536 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
11538 GList *redirects = NULL;
11540 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
11542 GstQtReference ref = { NULL, NULL, 0, 0 };
11543 GNode *rmdr, *rmvc;
11545 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
11546 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
11547 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
11548 ref.min_req_bitrate);
11551 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
11552 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
11553 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
11555 #ifndef GST_DISABLE_GST_DEBUG
11556 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
11558 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
11560 GST_LOG_OBJECT (qtdemux,
11561 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
11562 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
11563 bitmask, check_type);
11564 if (package == FOURCC_qtim && check_type == 0) {
11565 ref.min_req_qt_version = version;
11569 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
11575 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
11576 if (ref_len > 20) {
11577 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
11578 ref_data = (guint8 *) rdrf->data + 20;
11579 if (ref_type == FOURCC_alis) {
11580 guint record_len, record_version, fn_len;
11582 if (ref_len > 70) {
11583 /* MacOSX alias record, google for alias-layout.txt */
11584 record_len = QT_UINT16 (ref_data + 4);
11585 record_version = QT_UINT16 (ref_data + 4 + 2);
11586 fn_len = QT_UINT8 (ref_data + 50);
11587 if (record_len > 50 && record_version == 2 && fn_len > 0) {
11588 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
11591 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
11594 } else if (ref_type == FOURCC_url_) {
11595 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
11597 GST_DEBUG_OBJECT (qtdemux,
11598 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
11599 GST_FOURCC_ARGS (ref_type));
11601 if (ref.location != NULL) {
11602 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
11604 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
11606 GST_WARNING_OBJECT (qtdemux,
11607 "Failed to extract redirect location from rdrf atom");
11610 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
11614 /* look for others */
11615 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
11618 if (redirects != NULL) {
11619 qtdemux_process_redirects (qtdemux, redirects);
11625 static GstTagList *
11626 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
11630 if (tags == NULL) {
11631 tags = gst_tag_list_new_empty ();
11632 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
11635 if (qtdemux->major_brand == FOURCC_mjp2)
11636 fmt = "Motion JPEG 2000";
11637 else if ((qtdemux->major_brand & 0xffff) == GST_MAKE_FOURCC ('3', 'g', 0, 0))
11639 else if (qtdemux->major_brand == FOURCC_qt__)
11641 else if (qtdemux->fragmented)
11644 fmt = "ISO MP4/M4A";
11646 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
11647 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
11649 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
11655 /* we have read th complete moov node now.
11656 * This function parses all of the relevant info, creates the traks and
11657 * prepares all data structures for playback
11660 qtdemux_parse_tree (GstQTDemux * qtdemux)
11666 GstClockTime duration;
11668 guint64 creation_time;
11669 GstDateTime *datetime = NULL;
11672 /* make sure we have a usable taglist */
11673 if (!qtdemux->tag_list) {
11674 qtdemux->tag_list = gst_tag_list_new_empty ();
11675 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
11677 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
11680 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
11681 if (mvhd == NULL) {
11682 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
11683 return qtdemux_parse_redirects (qtdemux);
11686 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
11687 if (version == 1) {
11688 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
11689 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
11690 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
11691 } else if (version == 0) {
11692 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
11693 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
11694 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
11696 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
11700 /* Moving qt creation time (secs since 1904) to unix time */
11701 if (creation_time != 0) {
11702 /* Try to use epoch first as it should be faster and more commonly found */
11703 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
11706 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
11707 /* some data cleansing sanity */
11708 g_get_current_time (&now);
11709 if (now.tv_sec + 24 * 3600 < creation_time) {
11710 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
11712 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
11715 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
11716 GDateTime *dt, *dt_local;
11718 dt = g_date_time_add_seconds (base_dt, creation_time);
11719 dt_local = g_date_time_to_local (dt);
11720 datetime = gst_date_time_new_from_g_date_time (dt_local);
11722 g_date_time_unref (base_dt);
11723 g_date_time_unref (dt);
11727 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
11728 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
11730 gst_date_time_unref (datetime);
11733 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
11734 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
11736 /* check for fragmented file and get some (default) data */
11737 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
11740 GstByteReader mehd_data;
11742 /* let track parsing or anyone know weird stuff might happen ... */
11743 qtdemux->fragmented = TRUE;
11745 /* compensate for total duration */
11746 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
11748 qtdemux_parse_mehd (qtdemux, &mehd_data);
11751 /* set duration in the segment info */
11752 gst_qtdemux_get_duration (qtdemux, &duration);
11754 qtdemux->segment.duration = duration;
11755 /* also do not exceed duration; stop is set that way post seek anyway,
11756 * and segment activation falls back to duration,
11757 * whereas loop only checks stop, so let's align this here as well */
11758 qtdemux->segment.stop = duration;
11761 /* parse all traks */
11762 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
11764 qtdemux_parse_trak (qtdemux, trak);
11765 /* iterate all siblings */
11766 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
11769 if (!qtdemux->tag_list) {
11770 GST_DEBUG_OBJECT (qtdemux, "new tag list");
11771 qtdemux->tag_list = gst_tag_list_new_empty ();
11772 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
11774 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
11778 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
11780 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
11782 GST_LOG_OBJECT (qtdemux, "No udta node found.");
11785 /* maybe also some tags in meta box */
11786 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
11788 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
11789 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
11791 GST_LOG_OBJECT (qtdemux, "No meta node found.");
11794 /* parse any protection system info */
11795 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
11797 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
11798 qtdemux_parse_pssh (qtdemux, pssh);
11799 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
11802 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
11807 /* taken from ffmpeg */
11809 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
11821 len = (len << 7) | (c & 0x7f);
11829 /* this can change the codec originally present in @list */
11831 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
11832 GNode * esds, GstTagList * list)
11834 int len = QT_UINT32 (esds->data);
11835 guint8 *ptr = esds->data;
11836 guint8 *end = ptr + len;
11838 guint8 *data_ptr = NULL;
11840 guint8 object_type_id = 0;
11841 const char *codec_name = NULL;
11842 GstCaps *caps = NULL;
11844 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
11846 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
11848 while (ptr + 1 < end) {
11849 tag = QT_UINT8 (ptr);
11850 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
11852 len = read_descr_size (ptr, end, &ptr);
11853 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
11855 /* Check the stated amount of data is available for reading */
11856 if (len < 0 || ptr + len > end)
11860 case ES_DESCRIPTOR_TAG:
11861 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
11862 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
11865 case DECODER_CONFIG_DESC_TAG:{
11866 guint max_bitrate, avg_bitrate;
11868 object_type_id = QT_UINT8 (ptr);
11869 max_bitrate = QT_UINT32 (ptr + 5);
11870 avg_bitrate = QT_UINT32 (ptr + 9);
11871 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
11872 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
11873 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
11874 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
11875 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
11876 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
11877 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
11878 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
11880 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
11881 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
11882 avg_bitrate, NULL);
11887 case DECODER_SPECIFIC_INFO_TAG:
11888 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
11889 if (object_type_id == 0xe0 && len == 0x40) {
11895 GST_DEBUG_OBJECT (qtdemux,
11896 "Have VOBSUB palette. Creating palette event");
11897 /* move to decConfigDescr data and read palette */
11899 for (i = 0; i < 16; i++) {
11900 clut[i] = QT_UINT32 (data);
11904 s = gst_structure_new ("application/x-gst-dvd", "event",
11905 G_TYPE_STRING, "dvd-spu-clut-change",
11906 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
11907 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
11908 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
11909 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
11910 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
11911 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
11912 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
11913 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
11916 /* store event and trigger custom processing */
11917 stream->pending_event =
11918 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
11920 /* Generic codec_data handler puts it on the caps */
11927 case SL_CONFIG_DESC_TAG:
11928 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
11932 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
11934 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
11940 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
11941 * in use, and should also be used to override some other parameters for some
11943 switch (object_type_id) {
11944 case 0x20: /* MPEG-4 */
11945 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
11946 * profile_and_level_indication */
11947 if (data_ptr != NULL && data_len >= 5 &&
11948 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
11949 gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
11950 data_ptr + 4, data_len - 4);
11952 break; /* Nothing special needed here */
11953 case 0x21: /* H.264 */
11954 codec_name = "H.264 / AVC";
11955 caps = gst_caps_new_simple ("video/x-h264",
11956 "stream-format", G_TYPE_STRING, "avc",
11957 "alignment", G_TYPE_STRING, "au", NULL);
11959 case 0x40: /* AAC (any) */
11960 case 0x66: /* AAC Main */
11961 case 0x67: /* AAC LC */
11962 case 0x68: /* AAC SSR */
11963 /* Override channels and rate based on the codec_data, as it's often
11965 /* Only do so for basic setup without HE-AAC extension */
11966 if (data_ptr && data_len == 2) {
11967 guint channels, rateindex, rate;
11969 /* FIXME: add gst_codec_utils_aac_get_{channels|sample_rate}()? */
11970 channels = (data_ptr[1] & 0x7f) >> 3;
11971 if (channels > 0 && channels < 7) {
11972 stream->n_channels = channels;
11973 } else if (channels == 7) {
11974 stream->n_channels = 8;
11977 rateindex = ((data_ptr[0] & 0x7) << 1) | ((data_ptr[1] & 0x80) >> 7);
11978 rate = gst_codec_utils_aac_get_sample_rate_from_index (rateindex);
11980 stream->rate = rate;
11983 /* Set level and profile if possible */
11984 if (data_ptr != NULL && data_len >= 2) {
11985 gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
11986 data_ptr, data_len);
11989 case 0x60: /* MPEG-2, various profiles */
11995 codec_name = "MPEG-2 video";
11996 caps = gst_caps_new_simple ("video/mpeg",
11997 "mpegversion", G_TYPE_INT, 2,
11998 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12000 case 0x69: /* MPEG-2 BC audio */
12001 case 0x6B: /* MPEG-1 audio */
12002 caps = gst_caps_new_simple ("audio/mpeg",
12003 "mpegversion", G_TYPE_INT, 1, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
12004 codec_name = "MPEG-1 audio";
12006 case 0x6A: /* MPEG-1 */
12007 codec_name = "MPEG-1 video";
12008 caps = gst_caps_new_simple ("video/mpeg",
12009 "mpegversion", G_TYPE_INT, 1,
12010 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12012 case 0x6C: /* MJPEG */
12014 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
12016 codec_name = "Motion-JPEG";
12018 case 0x6D: /* PNG */
12020 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
12022 codec_name = "PNG still images";
12024 case 0x6E: /* JPEG2000 */
12025 codec_name = "JPEG-2000";
12026 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
12028 case 0xA4: /* Dirac */
12029 codec_name = "Dirac";
12030 caps = gst_caps_new_empty_simple ("video/x-dirac");
12032 case 0xA5: /* AC3 */
12033 codec_name = "AC-3 audio";
12034 caps = gst_caps_new_simple ("audio/x-ac3",
12035 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12037 case 0xA9: /* AC3 */
12038 codec_name = "DTS audio";
12039 caps = gst_caps_new_simple ("audio/x-dts",
12040 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12042 case 0xE1: /* QCELP */
12043 /* QCELP, the codec_data is a riff tag (little endian) with
12044 * 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). */
12045 caps = gst_caps_new_empty_simple ("audio/qcelp");
12046 codec_name = "QCELP";
12052 /* If we have a replacement caps, then change our caps for this stream */
12054 gst_caps_unref (stream->caps);
12055 stream->caps = caps;
12058 if (codec_name && list)
12059 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
12060 GST_TAG_AUDIO_CODEC, codec_name, NULL);
12062 /* Add the codec_data attribute to caps, if we have it */
12066 buffer = gst_buffer_new_and_alloc (data_len);
12067 gst_buffer_fill (buffer, 0, data_ptr, data_len);
12069 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
12070 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
12072 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
12074 gst_buffer_unref (buffer);
12079 #define _codec(name) \
12081 if (codec_name) { \
12082 *codec_name = g_strdup (name); \
12087 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
12088 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
12090 GstCaps *caps = NULL;
12091 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
12094 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
12095 _codec ("PNG still images");
12096 caps = gst_caps_new_empty_simple ("image/png");
12098 case GST_MAKE_FOURCC ('j', 'p', 'e', 'g'):
12099 _codec ("JPEG still images");
12101 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
12104 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
12105 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
12106 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
12107 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
12108 _codec ("Motion-JPEG");
12110 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
12113 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
12114 _codec ("Motion-JPEG format B");
12115 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
12117 case GST_MAKE_FOURCC ('m', 'j', 'p', '2'):
12118 _codec ("JPEG-2000");
12119 /* override to what it should be according to spec, avoid palette_data */
12120 stream->bits_per_sample = 24;
12121 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
12123 case GST_MAKE_FOURCC ('S', 'V', 'Q', '3'):
12124 _codec ("Sorensen video v.3");
12125 caps = gst_caps_new_simple ("video/x-svq",
12126 "svqversion", G_TYPE_INT, 3, NULL);
12128 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
12129 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
12130 _codec ("Sorensen video v.1");
12131 caps = gst_caps_new_simple ("video/x-svq",
12132 "svqversion", G_TYPE_INT, 1, NULL);
12134 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
12135 caps = gst_caps_new_empty_simple ("video/x-raw");
12136 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
12137 _codec ("Windows Raw RGB");
12139 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
12143 bps = QT_UINT16 (stsd_data + 98);
12146 format = GST_VIDEO_FORMAT_RGB15;
12149 format = GST_VIDEO_FORMAT_RGB16;
12152 format = GST_VIDEO_FORMAT_RGB;
12155 format = GST_VIDEO_FORMAT_ARGB;
12163 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
12164 format = GST_VIDEO_FORMAT_I420;
12166 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
12167 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
12168 format = GST_VIDEO_FORMAT_I420;
12170 case GST_MAKE_FOURCC ('2', 'v', 'u', 'y'):
12171 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
12172 format = GST_VIDEO_FORMAT_UYVY;
12174 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
12175 format = GST_VIDEO_FORMAT_v308;
12177 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
12178 format = GST_VIDEO_FORMAT_v216;
12180 case GST_MAKE_FOURCC ('v', '2', '1', '0'):
12181 format = GST_VIDEO_FORMAT_v210;
12183 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
12184 format = GST_VIDEO_FORMAT_r210;
12186 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
12187 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
12188 format = GST_VIDEO_FORMAT_v410;
12191 /* Packed YUV 4:4:4:4 8 bit in 32 bits
12192 * but different order than AYUV
12193 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
12194 format = GST_VIDEO_FORMAT_v408;
12197 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
12198 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
12199 _codec ("MPEG-1 video");
12200 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
12201 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12203 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
12204 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
12205 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
12206 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
12207 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
12208 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
12209 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
12210 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
12211 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
12212 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
12213 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
12214 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
12215 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
12216 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
12217 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
12218 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
12219 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
12220 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
12221 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
12222 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
12223 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
12224 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
12225 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
12226 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
12227 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
12228 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
12229 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
12230 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
12231 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
12232 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
12233 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
12234 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
12235 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
12236 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
12237 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
12238 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
12239 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
12240 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
12241 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
12242 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
12243 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
12244 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
12245 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
12246 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
12247 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
12248 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
12249 _codec ("MPEG-2 video");
12250 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
12251 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12253 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
12254 _codec ("GIF still images");
12255 caps = gst_caps_new_empty_simple ("image/gif");
12257 case GST_MAKE_FOURCC ('h', '2', '6', '3'):
12258 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
12259 case GST_MAKE_FOURCC ('s', '2', '6', '3'):
12260 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
12262 /* ffmpeg uses the height/width props, don't know why */
12263 caps = gst_caps_new_simple ("video/x-h263",
12264 "variant", G_TYPE_STRING, "itu", NULL);
12266 case GST_MAKE_FOURCC ('m', 'p', '4', 'v'):
12267 case GST_MAKE_FOURCC ('M', 'P', '4', 'V'):
12268 _codec ("MPEG-4 video");
12269 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
12270 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12272 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
12273 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
12274 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
12275 caps = gst_caps_new_simple ("video/x-msmpeg",
12276 "msmpegversion", G_TYPE_INT, 43, NULL);
12278 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
12280 caps = gst_caps_new_simple ("video/x-divx",
12281 "divxversion", G_TYPE_INT, 3, NULL);
12283 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
12284 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
12286 caps = gst_caps_new_simple ("video/x-divx",
12287 "divxversion", G_TYPE_INT, 4, NULL);
12289 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
12291 caps = gst_caps_new_simple ("video/x-divx",
12292 "divxversion", G_TYPE_INT, 5, NULL);
12295 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
12297 caps = gst_caps_new_simple ("video/x-ffv",
12298 "ffvversion", G_TYPE_INT, 1, NULL);
12301 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
12302 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
12303 case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
12304 case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
12305 case GST_MAKE_FOURCC ('F', 'M', 'P', '4'):
12306 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
12307 caps = gst_caps_new_simple ("video/mpeg",
12308 "mpegversion", G_TYPE_INT, 4, NULL);
12310 *codec_name = g_strdup ("MPEG-4");
12313 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
12314 _codec ("Cinepak");
12315 caps = gst_caps_new_empty_simple ("video/x-cinepak");
12317 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
12318 _codec ("Apple QuickDraw");
12319 caps = gst_caps_new_empty_simple ("video/x-qdrw");
12321 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
12322 _codec ("Apple video");
12323 caps = gst_caps_new_empty_simple ("video/x-apple-video");
12325 case GST_MAKE_FOURCC ('H', '2', '6', '4'):
12326 case GST_MAKE_FOURCC ('a', 'v', 'c', '1'):
12327 _codec ("H.264 / AVC");
12328 caps = gst_caps_new_simple ("video/x-h264",
12329 "stream-format", G_TYPE_STRING, "avc",
12330 "alignment", G_TYPE_STRING, "au", NULL);
12332 case GST_MAKE_FOURCC ('a', 'v', 'c', '3'):
12333 _codec ("H.264 / AVC");
12334 caps = gst_caps_new_simple ("video/x-h264",
12335 "stream-format", G_TYPE_STRING, "avc3",
12336 "alignment", G_TYPE_STRING, "au", NULL);
12338 case GST_MAKE_FOURCC ('H', '2', '6', '5'):
12339 case GST_MAKE_FOURCC ('h', 'v', 'c', '1'):
12340 _codec ("H.265 / HEVC");
12341 caps = gst_caps_new_simple ("video/x-h265",
12342 "stream-format", G_TYPE_STRING, "hvc1",
12343 "alignment", G_TYPE_STRING, "au", NULL);
12345 case GST_MAKE_FOURCC ('h', 'e', 'v', '1'):
12346 _codec ("H.265 / HEVC");
12347 caps = gst_caps_new_simple ("video/x-h265",
12348 "stream-format", G_TYPE_STRING, "hev1",
12349 "alignment", G_TYPE_STRING, "au", NULL);
12351 case GST_MAKE_FOURCC ('r', 'l', 'e', ' '):
12352 _codec ("Run-length encoding");
12353 caps = gst_caps_new_simple ("video/x-rle",
12354 "layout", G_TYPE_STRING, "quicktime", NULL);
12356 case GST_MAKE_FOURCC ('W', 'R', 'L', 'E'):
12357 _codec ("Run-length encoding");
12358 caps = gst_caps_new_simple ("video/x-rle",
12359 "layout", G_TYPE_STRING, "microsoft", NULL);
12361 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
12362 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
12363 _codec ("Indeo Video 3");
12364 caps = gst_caps_new_simple ("video/x-indeo",
12365 "indeoversion", G_TYPE_INT, 3, NULL);
12367 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
12368 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
12369 _codec ("Intel Video 4");
12370 caps = gst_caps_new_simple ("video/x-indeo",
12371 "indeoversion", G_TYPE_INT, 4, NULL);
12373 case GST_MAKE_FOURCC ('d', 'v', 'c', 'p'):
12374 case GST_MAKE_FOURCC ('d', 'v', 'c', ' '):
12375 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
12376 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
12377 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
12378 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
12379 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
12380 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
12381 _codec ("DV Video");
12382 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
12383 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12385 case GST_MAKE_FOURCC ('d', 'v', '5', 'n'): /* DVCPRO50 NTSC */
12386 case GST_MAKE_FOURCC ('d', 'v', '5', 'p'): /* DVCPRO50 PAL */
12387 _codec ("DVCPro50 Video");
12388 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
12389 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12391 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
12392 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
12393 _codec ("DVCProHD Video");
12394 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
12395 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12397 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
12398 _codec ("Apple Graphics (SMC)");
12399 caps = gst_caps_new_empty_simple ("video/x-smc");
12401 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
12403 caps = gst_caps_new_empty_simple ("video/x-vp3");
12405 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
12406 _codec ("VP6 Flash");
12407 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
12409 case GST_MAKE_FOURCC ('X', 'i', 'T', 'h'):
12411 caps = gst_caps_new_empty_simple ("video/x-theora");
12412 /* theora uses one byte of padding in the data stream because it does not
12413 * allow 0 sized packets while theora does */
12414 stream->padding = 1;
12416 case GST_MAKE_FOURCC ('d', 'r', 'a', 'c'):
12418 caps = gst_caps_new_empty_simple ("video/x-dirac");
12420 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
12421 _codec ("TIFF still images");
12422 caps = gst_caps_new_empty_simple ("image/tiff");
12424 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
12425 _codec ("Apple Intermediate Codec");
12426 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
12428 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
12429 _codec ("AVID DNxHD");
12430 caps = gst_caps_from_string ("video/x-dnxhd");
12432 case GST_MAKE_FOURCC ('V', 'P', '8', '0'):
12433 _codec ("On2 VP8");
12434 caps = gst_caps_from_string ("video/x-vp8");
12436 case GST_MAKE_FOURCC ('a', 'p', 'c', 's'):
12437 _codec ("Apple ProRes LT");
12439 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
12442 case GST_MAKE_FOURCC ('a', 'p', 'c', 'h'):
12443 _codec ("Apple ProRes HQ");
12445 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
12448 case GST_MAKE_FOURCC ('a', 'p', 'c', 'n'):
12449 _codec ("Apple ProRes");
12451 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
12454 case GST_MAKE_FOURCC ('a', 'p', 'c', 'o'):
12455 _codec ("Apple ProRes Proxy");
12457 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
12460 case GST_MAKE_FOURCC ('a', 'p', '4', 'h'):
12461 _codec ("Apple ProRes 4444");
12463 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
12466 case GST_MAKE_FOURCC ('v', 'c', '-', '1'):
12469 caps = gst_caps_new_simple ("video/x-wmv",
12470 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
12472 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
12475 char *s, fourstr[5];
12477 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12478 s = g_strdup_printf ("video/x-gst-fourcc-%s", g_strstrip (fourstr));
12479 caps = gst_caps_new_empty_simple (s);
12485 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
12488 gst_video_info_init (&info);
12489 gst_video_info_set_format (&info, format, stream->width, stream->height);
12491 caps = gst_video_info_to_caps (&info);
12492 *codec_name = gst_pb_utils_get_codec_description (caps);
12494 /* enable clipping for raw video streams */
12495 stream->need_clip = TRUE;
12502 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
12503 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
12506 const GstStructure *s;
12509 GstAudioFormat format = 0;
12512 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
12514 depth = stream->bytes_per_packet * 8;
12517 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
12518 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
12519 /* 8-bit audio is unsigned */
12521 format = GST_AUDIO_FORMAT_U8;
12522 /* otherwise it's signed and big-endian just like 'twos' */
12523 case GST_MAKE_FOURCC ('t', 'w', 'o', 's'):
12524 endian = G_BIG_ENDIAN;
12526 case GST_MAKE_FOURCC ('s', 'o', 'w', 't'):
12531 endian = G_LITTLE_ENDIAN;
12534 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
12536 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
12540 caps = gst_caps_new_simple ("audio/x-raw",
12541 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
12542 "layout", G_TYPE_STRING, "interleaved", NULL);
12545 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
12546 _codec ("Raw 64-bit floating-point audio");
12547 caps = gst_caps_new_simple ("audio/x-raw",
12548 "format", G_TYPE_STRING, "F64BE",
12549 "layout", G_TYPE_STRING, "interleaved", NULL);
12551 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
12552 _codec ("Raw 32-bit floating-point audio");
12553 caps = gst_caps_new_simple ("audio/x-raw",
12554 "format", G_TYPE_STRING, "F32BE",
12555 "layout", G_TYPE_STRING, "interleaved", NULL);
12558 _codec ("Raw 24-bit PCM audio");
12559 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
12561 caps = gst_caps_new_simple ("audio/x-raw",
12562 "format", G_TYPE_STRING, "S24BE",
12563 "layout", G_TYPE_STRING, "interleaved", NULL);
12565 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
12566 _codec ("Raw 32-bit PCM audio");
12567 caps = gst_caps_new_simple ("audio/x-raw",
12568 "format", G_TYPE_STRING, "S32BE",
12569 "layout", G_TYPE_STRING, "interleaved", NULL);
12571 case GST_MAKE_FOURCC ('u', 'l', 'a', 'w'):
12572 _codec ("Mu-law audio");
12573 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
12575 case GST_MAKE_FOURCC ('a', 'l', 'a', 'w'):
12576 _codec ("A-law audio");
12577 caps = gst_caps_new_empty_simple ("audio/x-alaw");
12581 _codec ("Microsoft ADPCM");
12582 /* Microsoft ADPCM-ACM code 2 */
12583 caps = gst_caps_new_simple ("audio/x-adpcm",
12584 "layout", G_TYPE_STRING, "microsoft", NULL);
12588 _codec ("DVI/IMA ADPCM");
12589 caps = gst_caps_new_simple ("audio/x-adpcm",
12590 "layout", G_TYPE_STRING, "dvi", NULL);
12594 _codec ("DVI/Intel IMA ADPCM");
12595 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
12596 caps = gst_caps_new_simple ("audio/x-adpcm",
12597 "layout", G_TYPE_STRING, "quicktime", NULL);
12601 /* MPEG layer 3, CBR only (pre QT4.1) */
12602 case GST_MAKE_FOURCC ('.', 'm', 'p', '3'):
12603 _codec ("MPEG-1 layer 3");
12604 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
12605 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
12606 "mpegversion", G_TYPE_INT, 1, NULL);
12609 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
12610 _codec ("EAC-3 audio");
12611 caps = gst_caps_new_simple ("audio/x-eac3",
12612 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12613 stream->sampled = TRUE;
12615 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
12616 case GST_MAKE_FOURCC ('a', 'c', '-', '3'):
12617 _codec ("AC-3 audio");
12618 caps = gst_caps_new_simple ("audio/x-ac3",
12619 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12620 stream->sampled = TRUE;
12622 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
12623 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
12624 _codec ("DTS audio");
12625 caps = gst_caps_new_simple ("audio/x-dts",
12626 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12627 stream->sampled = TRUE;
12629 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
12630 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
12631 _codec ("DTS-HD audio");
12632 caps = gst_caps_new_simple ("audio/x-dts",
12633 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12634 stream->sampled = TRUE;
12636 case GST_MAKE_FOURCC ('M', 'A', 'C', '3'):
12638 caps = gst_caps_new_simple ("audio/x-mace",
12639 "maceversion", G_TYPE_INT, 3, NULL);
12641 case GST_MAKE_FOURCC ('M', 'A', 'C', '6'):
12643 caps = gst_caps_new_simple ("audio/x-mace",
12644 "maceversion", G_TYPE_INT, 6, NULL);
12646 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
12648 caps = gst_caps_new_empty_simple ("application/ogg");
12650 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
12651 _codec ("DV audio");
12652 caps = gst_caps_new_empty_simple ("audio/x-dv");
12654 case GST_MAKE_FOURCC ('m', 'p', '4', 'a'):
12655 _codec ("MPEG-4 AAC audio");
12656 caps = gst_caps_new_simple ("audio/mpeg",
12657 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
12658 "stream-format", G_TYPE_STRING, "raw", NULL);
12660 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
12661 _codec ("QDesign Music");
12662 caps = gst_caps_new_empty_simple ("audio/x-qdm");
12664 case GST_MAKE_FOURCC ('Q', 'D', 'M', '2'):
12665 _codec ("QDesign Music v.2");
12666 /* FIXME: QDesign music version 2 (no constant) */
12667 if (FALSE && data) {
12668 caps = gst_caps_new_simple ("audio/x-qdm2",
12669 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
12670 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
12671 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
12673 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
12676 case GST_MAKE_FOURCC ('a', 'g', 's', 'm'):
12677 _codec ("GSM audio");
12678 caps = gst_caps_new_empty_simple ("audio/x-gsm");
12680 case GST_MAKE_FOURCC ('s', 'a', 'm', 'r'):
12681 _codec ("AMR audio");
12682 caps = gst_caps_new_empty_simple ("audio/AMR");
12684 case GST_MAKE_FOURCC ('s', 'a', 'w', 'b'):
12685 _codec ("AMR-WB audio");
12686 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
12688 case GST_MAKE_FOURCC ('i', 'm', 'a', '4'):
12689 _codec ("Quicktime IMA ADPCM");
12690 caps = gst_caps_new_simple ("audio/x-adpcm",
12691 "layout", G_TYPE_STRING, "quicktime", NULL);
12693 case GST_MAKE_FOURCC ('a', 'l', 'a', 'c'):
12694 _codec ("Apple lossless audio");
12695 caps = gst_caps_new_empty_simple ("audio/x-alac");
12697 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
12698 _codec ("QualComm PureVoice");
12699 caps = gst_caps_from_string ("audio/qcelp");
12701 case GST_MAKE_FOURCC ('w', 'm', 'a', ' '):
12704 caps = gst_caps_new_empty_simple ("audio/x-wma");
12706 case GST_MAKE_FOURCC ('l', 'p', 'c', 'm'):
12711 GstAudioFormat format;
12714 FLAG_IS_FLOAT = 0x1,
12715 FLAG_IS_BIG_ENDIAN = 0x2,
12716 FLAG_IS_SIGNED = 0x4,
12717 FLAG_IS_PACKED = 0x8,
12718 FLAG_IS_ALIGNED_HIGH = 0x10,
12719 FLAG_IS_NON_INTERLEAVED = 0x20
12721 _codec ("Raw LPCM audio");
12723 if (data && len >= 56) {
12724 depth = QT_UINT32 (data + 40);
12725 flags = QT_UINT32 (data + 44);
12726 width = QT_UINT32 (data + 48) * 8 / stream->n_channels;
12728 if ((flags & FLAG_IS_FLOAT) == 0) {
12733 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
12734 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
12735 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
12736 caps = gst_caps_new_simple ("audio/x-raw",
12737 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
12738 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
12739 "non-interleaved" : "interleaved", NULL);
12744 if (flags & FLAG_IS_BIG_ENDIAN)
12745 format = GST_AUDIO_FORMAT_F64BE;
12747 format = GST_AUDIO_FORMAT_F64LE;
12749 if (flags & FLAG_IS_BIG_ENDIAN)
12750 format = GST_AUDIO_FORMAT_F32BE;
12752 format = GST_AUDIO_FORMAT_F32LE;
12754 caps = gst_caps_new_simple ("audio/x-raw",
12755 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
12756 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
12757 "non-interleaved" : "interleaved", NULL);
12761 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
12765 char *s, fourstr[5];
12767 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12768 s = g_strdup_printf ("audio/x-gst-fourcc-%s", g_strstrip (fourstr));
12769 caps = gst_caps_new_empty_simple (s);
12776 GstCaps *templ_caps =
12777 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
12778 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
12779 gst_caps_unref (caps);
12780 gst_caps_unref (templ_caps);
12781 caps = intersection;
12784 /* enable clipping for raw audio streams */
12785 s = gst_caps_get_structure (caps, 0);
12786 name = gst_structure_get_name (s);
12787 if (g_str_has_prefix (name, "audio/x-raw")) {
12788 stream->need_clip = TRUE;
12789 stream->max_buffer_size = 4096 * stream->bytes_per_frame;
12790 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
12796 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
12797 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
12801 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
12804 case GST_MAKE_FOURCC ('m', 'p', '4', 's'):
12805 _codec ("DVD subtitle");
12806 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
12807 stream->need_process = TRUE;
12809 case GST_MAKE_FOURCC ('t', 'e', 'x', 't'):
12810 _codec ("Quicktime timed text");
12812 case GST_MAKE_FOURCC ('t', 'x', '3', 'g'):
12813 _codec ("3GPP timed text");
12815 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
12817 /* actual text piece needs to be extracted */
12818 stream->need_process = TRUE;
12821 _codec ("XML subtitles");
12822 caps = gst_caps_new_empty_simple ("application/ttml+xml");
12826 char *s, fourstr[5];
12828 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12829 s = g_strdup_printf ("text/x-gst-fourcc-%s", g_strstrip (fourstr));
12830 caps = gst_caps_new_empty_simple (s);
12839 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
12840 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
12845 case GST_MAKE_FOURCC ('m', '1', 'v', ' '):
12846 _codec ("MPEG 1 video");
12847 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
12848 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12858 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
12859 const gchar * system_id)
12863 if (!qtdemux->protection_system_ids)
12864 qtdemux->protection_system_ids =
12865 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
12866 /* Check whether we already have an entry for this system ID. */
12867 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
12868 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
12869 if (g_ascii_strcasecmp (system_id, id) == 0) {
12873 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
12874 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,