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
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Library General Public
14 * License as published by the Free Software Foundation; either
15 * version 2 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Library General Public License for more details.
22 * You should have received a copy of the GNU Library General Public
23 * License along with this library; if not, write to the
24 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
25 * Boston, MA 02110-1301, USA.
29 * SECTION:element-qtdemux
31 * Demuxes a .mov file into raw or compressed audio and/or video streams.
33 * This element supports both push and pull-based scheduling, depending on the
34 * capabilities of the upstream elements.
37 * <title>Example launch line</title>
39 * gst-launch-1.0 filesrc location=test.mov ! qtdemux name=demux demux.audio_0 ! decodebin ! audioconvert ! audioresample ! autoaudiosink demux.video_0 ! queue ! decodebin ! videoconvert ! videoscale ! autovideosink
40 * ]| Play (parse and decode) a .mov file and try to output it to
41 * an automatically detected soundcard and videosink. If the MOV file contains
42 * compressed audio or video data, this will only work if you have the
43 * right decoder elements/plugins installed.
51 #include "gst/gst-i18n-plugin.h"
53 #include <glib/gprintf.h>
54 #include <gst/tag/tag.h>
55 #include <gst/audio/audio.h>
56 #include <gst/video/video.h>
58 #include "qtatomparser.h"
59 #include "qtdemux_types.h"
60 #include "qtdemux_dump.h"
62 #include "descriptors.h"
63 #include "qtdemux_lang.h"
65 #include "qtpalette.h"
67 #include "gst/riff/riff-media.h"
68 #include "gst/riff/riff-read.h"
70 #include <gst/pbutils/pbutils.h>
77 #include <gst/math-compat.h>
83 /* max. size considered 'sane' for non-mdat atoms */
84 #define QTDEMUX_MAX_ATOM_SIZE (25*1024*1024)
86 /* if the sample index is larger than this, something is likely wrong */
87 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (50*1024*1024)
89 /* For converting qt creation times to unix epoch times */
90 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
91 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
92 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
93 QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
95 #define STREAM_IS_EOS(s) (s->time_position == GST_CLOCK_TIME_NONE)
97 GST_DEBUG_CATEGORY (qtdemux_debug);
99 /*typedef struct _QtNode QtNode; */
100 typedef struct _QtDemuxSegment QtDemuxSegment;
101 typedef struct _QtDemuxSample QtDemuxSample;
110 struct _QtDemuxSample
113 gint32 pts_offset; /* Add this value to timestamp to get the pts */
115 guint64 timestamp; /* DTS In mov time */
116 guint32 duration; /* In mov time */
117 gboolean keyframe; /* TRUE when this packet is a keyframe */
120 /* Macros for converting to/from timescale */
121 #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale))
122 #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND))
124 #define QTTIME_TO_GSTTIME(qtdemux, value) (gst_util_uint64_scale((value), GST_SECOND, (qtdemux)->timescale))
125 #define GSTTIME_TO_QTTIME(qtdemux, value) (gst_util_uint64_scale((value), (qtdemux)->timescale, GST_SECOND))
127 /* timestamp is the DTS */
128 #define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp))
129 /* timestamp + offset is the PTS */
130 #define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (sample)->pts_offset))
131 /* timestamp + duration - dts is the duration */
132 #define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts))
134 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
137 * Quicktime has tracks and segments. A track is a continuous piece of
138 * multimedia content. The track is not always played from start to finish but
139 * instead, pieces of the track are 'cut out' and played in sequence. This is
140 * what the segments do.
142 * Inside the track we have keyframes (K) and delta frames. The track has its
143 * own timing, which starts from 0 and extends to end. The position in the track
144 * is called the media_time.
146 * The segments now describe the pieces that should be played from this track
147 * and are basically tuples of media_time/duration/rate entries. We can have
148 * multiple segments and they are all played after one another. An example:
150 * segment 1: media_time: 1 second, duration: 1 second, rate 1
151 * segment 2: media_time: 3 second, duration: 2 second, rate 2
153 * To correctly play back this track, one must play: 1 second of media starting
154 * from media_time 1 followed by 2 seconds of media starting from media_time 3
157 * Each of the segments will be played at a specific time, the first segment at
158 * time 0, the second one after the duration of the first one, etc.. Note that
159 * the time in resulting playback is not identical to the media_time of the
162 * Visually, assuming the track has 4 second of media_time:
165 * .-----------------------------------------------------------.
166 * track: | K.....K.........K........K.......K.......K...........K... |
167 * '-----------------------------------------------------------'
169 * .------------^ ^ .----------^ ^
170 * / .-------------' / .------------------'
172 * .--------------. .--------------.
173 * | segment 1 | | segment 2 |
174 * '--------------' '--------------'
176 * The challenge here is to cut out the right pieces of the track for each of
177 * the playback segments. This fortunately can easily be done with the SEGMENT
178 * events of GStreamer.
180 * For playback of segment 1, we need to provide the decoder with the keyframe
181 * (a), in the above figure, but we must instruct it only to output the decoded
182 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
183 * position set to the time of the segment: 0.
185 * We then proceed to push data from keyframe (a) to frame (b). The decoder
186 * decodes but clips all before media_time 1.
188 * After finishing a segment, we push out a new SEGMENT event with the clipping
189 * boundaries of the new data.
191 * This is a good usecase for the GStreamer accumulated SEGMENT events.
194 struct _QtDemuxSegment
196 /* global time and duration, all gst time */
198 GstClockTime stop_time;
199 GstClockTime duration;
200 /* media time of trak, all gst time */
201 GstClockTime media_start;
202 GstClockTime media_stop;
204 /* Media start time in trak timescale units */
205 guint32 trak_media_start;
208 #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
210 /* Used with fragmented MP4 files (mfra atom) */
215 } QtDemuxRandomAccessEntry;
217 struct _QtDemuxStream
228 gboolean new_stream; /* signals that a stream_start is required */
229 gboolean on_keyframe; /* if this stream last pushed buffer was a
230 * keyframe. This is important to identify
231 * where to stop pushing buffers after a
232 * segment stop time */
234 /* if the stream has a redirect URI in its headers, we store it here */
241 guint64 duration; /* in timescale */
245 gchar lang_id[4]; /* ISO 639-2T language code */
249 QtDemuxSample *samples;
250 gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */
251 guint32 first_duration; /* duration in timescale of first sample, used for figuring out
252 the framerate, in timescale units */
253 guint32 offset_in_sample;
254 guint32 max_buffer_size;
256 /* if we use chunks or samples */
268 /* Numerator/denominator framerate */
271 guint16 bits_per_sample;
272 guint16 color_table_id;
273 GstMemory *rgb8_palette;
278 guint samples_per_packet;
279 guint samples_per_frame;
280 guint bytes_per_packet;
281 guint bytes_per_sample;
282 guint bytes_per_frame;
286 gboolean use_allocator;
287 GstAllocator *allocator;
288 GstAllocationParams params;
290 /* when a discontinuity is pending */
293 /* list of buffers to push first */
296 /* if we need to clip this buffer. This is only needed for uncompressed
300 /* buffer needs some custom processing, e.g. subtitles */
301 gboolean need_process;
303 /* current position */
304 guint32 segment_index;
305 guint32 sample_index;
306 GstClockTime time_position; /* in gst time */
308 /* the Gst segment we are processing out, used for clipping */
310 guint32 segment_seqnum; /* segment event seqnum obtained from seek */
312 /* quicktime segments */
314 QtDemuxSegment *segments;
315 gboolean dummy_segment;
320 GstTagList *pending_tags;
321 gboolean send_global_tags;
323 GstEvent *pending_event;
333 gboolean chunks_are_samples; /* TRUE means treat chunks as samples */
337 GstByteReader co_chunk;
339 guint32 current_chunk;
341 guint32 samples_per_chunk;
342 guint32 stco_sample_index;
344 guint32 sample_size; /* 0 means variable sizes are stored in stsz */
347 guint32 n_samples_per_chunk;
348 guint32 stsc_chunk_index;
349 guint32 stsc_sample_index;
350 guint64 chunk_offset;
353 guint32 stts_samples;
354 guint32 n_sample_times;
355 guint32 stts_sample_index;
357 guint32 stts_duration;
359 gboolean stss_present;
360 guint32 n_sample_syncs;
363 gboolean stps_present;
364 guint32 n_sample_partial_syncs;
366 QtDemuxRandomAccessEntry *ra_entries;
369 const QtDemuxRandomAccessEntry *pending_seek;
372 gboolean ctts_present;
373 guint32 n_composition_times;
375 guint32 ctts_sample_index;
380 gboolean parsed_trex;
381 guint32 def_sample_duration;
382 guint32 def_sample_size;
383 guint32 def_sample_flags;
390 QTDEMUX_STATE_INITIAL, /* Initial state (haven't got the header yet) */
391 QTDEMUX_STATE_HEADER, /* Parsing the header */
392 QTDEMUX_STATE_MOVIE, /* Parsing/Playing the media data */
393 QTDEMUX_STATE_BUFFER_MDAT /* Buffering the mdat atom */
396 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
397 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
398 guint32 fourcc, GstByteReader * parser);
399 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
400 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
401 guint32 fourcc, GstByteReader * parser);
403 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
405 static GstStaticPadTemplate gst_qtdemux_sink_template =
406 GST_STATIC_PAD_TEMPLATE ("sink",
409 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
413 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
414 GST_STATIC_PAD_TEMPLATE ("video_%u",
417 GST_STATIC_CAPS_ANY);
419 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
420 GST_STATIC_PAD_TEMPLATE ("audio_%u",
423 GST_STATIC_CAPS_ANY);
425 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
426 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
429 GST_STATIC_CAPS_ANY);
431 #define gst_qtdemux_parent_class parent_class
432 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
434 static void gst_qtdemux_dispose (GObject * object);
437 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
438 GstClockTime media_time);
440 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
441 QtDemuxStream * str, gint64 media_offset);
444 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
445 static GstIndex *gst_qtdemux_get_index (GstElement * element);
447 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
448 GstStateChange transition);
449 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
450 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
451 GstObject * parent, GstPadMode mode, gboolean active);
453 static void gst_qtdemux_loop (GstPad * pad);
454 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
456 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
458 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
459 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
460 QtDemuxStream * stream);
461 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
464 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
465 const guint8 * buffer, guint length);
466 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
467 const guint8 * buffer, guint length);
468 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
470 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
471 QtDemuxStream * stream, GNode * esds, GstTagList * list);
472 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
473 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
474 gchar ** codec_name);
475 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
476 QtDemuxStream * stream, guint32 fourcc, const guint8 * data, int len,
477 gchar ** codec_name);
478 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux,
479 QtDemuxStream * stream, guint32 fourcc, const guint8 * data,
480 gchar ** codec_name);
481 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
482 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
483 gchar ** codec_name);
485 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
486 QtDemuxStream * stream, guint32 n);
487 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
488 static void gst_qtdemux_stream_free (GstQTDemux * qtdemux,
489 QtDemuxStream * stream);
490 static void gst_qtdemux_stream_clear (GstQTDemux * qtdemux,
491 QtDemuxStream * stream);
492 static void gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int index);
493 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
494 static void qtdemux_do_allocation (GstQTDemux * qtdemux,
495 QtDemuxStream * stream);
497 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
500 gst_qtdemux_class_init (GstQTDemuxClass * klass)
502 GObjectClass *gobject_class;
503 GstElementClass *gstelement_class;
505 gobject_class = (GObjectClass *) klass;
506 gstelement_class = (GstElementClass *) klass;
508 parent_class = g_type_class_peek_parent (klass);
510 gobject_class->dispose = gst_qtdemux_dispose;
512 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
514 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
515 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
518 gst_tag_register_musicbrainz_tags ();
520 gst_element_class_add_pad_template (gstelement_class,
521 gst_static_pad_template_get (&gst_qtdemux_sink_template));
522 gst_element_class_add_pad_template (gstelement_class,
523 gst_static_pad_template_get (&gst_qtdemux_videosrc_template));
524 gst_element_class_add_pad_template (gstelement_class,
525 gst_static_pad_template_get (&gst_qtdemux_audiosrc_template));
526 gst_element_class_add_pad_template (gstelement_class,
527 gst_static_pad_template_get (&gst_qtdemux_subsrc_template));
528 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
530 "Demultiplex a QuickTime file into audio and video streams",
531 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
533 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
538 gst_qtdemux_init (GstQTDemux * qtdemux)
541 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
542 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
543 gst_pad_set_activatemode_function (qtdemux->sinkpad,
544 qtdemux_sink_activate_mode);
545 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
546 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
547 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
549 qtdemux->state = QTDEMUX_STATE_INITIAL;
550 qtdemux->pullbased = FALSE;
551 qtdemux->posted_redirect = FALSE;
552 qtdemux->neededbytes = 16;
554 qtdemux->adapter = gst_adapter_new ();
556 qtdemux->first_mdat = -1;
557 qtdemux->got_moov = FALSE;
558 qtdemux->mdatoffset = -1;
559 qtdemux->mdatbuffer = NULL;
560 qtdemux->restoredata_buffer = NULL;
561 qtdemux->restoredata_offset = -1;
562 qtdemux->fragment_start = -1;
563 qtdemux->fragment_start_offset = -1;
564 qtdemux->media_caps = NULL;
565 qtdemux->exposed = FALSE;
566 qtdemux->mss_mode = FALSE;
567 qtdemux->pending_newsegment = NULL;
568 qtdemux->upstream_newsegment = FALSE;
569 qtdemux->have_group_id = FALSE;
570 qtdemux->group_id = G_MAXUINT;
571 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
572 qtdemux->flowcombiner = gst_flow_combiner_new ();
574 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
578 gst_qtdemux_dispose (GObject * object)
580 GstQTDemux *qtdemux = GST_QTDEMUX (object);
582 if (qtdemux->adapter) {
583 g_object_unref (G_OBJECT (qtdemux->adapter));
584 qtdemux->adapter = NULL;
586 gst_flow_combiner_free (qtdemux->flowcombiner);
588 G_OBJECT_CLASS (parent_class)->dispose (object);
592 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
594 if (qtdemux->posted_redirect) {
595 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
596 (_("This file contains no playable streams.")),
597 ("no known streams found, a redirect message has been posted"));
599 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
600 (_("This file contains no playable streams.")),
601 ("no known streams found"));
606 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
608 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
609 mem, size, 0, size, mem, free_func);
613 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
620 if (G_UNLIKELY (size == 0)) {
622 GstBuffer *tmp = NULL;
624 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
625 if (ret != GST_FLOW_OK)
628 gst_buffer_map (tmp, &map, GST_MAP_READ);
629 size = QT_UINT32 (map.data);
630 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
632 gst_buffer_unmap (tmp, &map);
633 gst_buffer_unref (tmp);
636 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
637 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
638 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
639 /* we're pulling header but already got most interesting bits,
640 * so never mind the rest (e.g. tags) (that much) */
641 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
645 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
646 (_("This file is invalid and cannot be played.")),
647 ("atom has bogus size %" G_GUINT64_FORMAT, size));
648 return GST_FLOW_ERROR;
652 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
654 if (G_UNLIKELY (flow != GST_FLOW_OK))
657 bsize = gst_buffer_get_size (*buf);
658 /* Catch short reads - we don't want any partial atoms */
659 if (G_UNLIKELY (bsize < size)) {
660 GST_WARNING_OBJECT (qtdemux,
661 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
662 gst_buffer_unref (*buf);
672 gst_qtdemux_src_convert (GstPad * pad, GstFormat src_format, gint64 src_value,
673 GstFormat dest_format, gint64 * dest_value)
676 QtDemuxStream *stream = gst_pad_get_element_private (pad);
677 GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
680 if (stream->subtype != FOURCC_vide) {
685 switch (src_format) {
686 case GST_FORMAT_TIME:
687 switch (dest_format) {
688 case GST_FORMAT_BYTES:{
689 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
693 *dest_value = stream->samples[index].offset;
695 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
696 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
697 GST_TIME_ARGS (src_value), *dest_value);
705 case GST_FORMAT_BYTES:
706 switch (dest_format) {
707 case GST_FORMAT_TIME:{
709 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
716 QTSTREAMTIME_TO_GSTTIME (stream,
717 stream->samples[index].timestamp);
718 GST_DEBUG_OBJECT (qtdemux,
719 "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
720 GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
733 gst_object_unref (qtdemux);
740 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
744 *duration = GST_CLOCK_TIME_NONE;
746 if (qtdemux->duration != 0) {
747 if (qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
748 *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
755 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
758 gboolean res = FALSE;
759 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
761 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
763 switch (GST_QUERY_TYPE (query)) {
764 case GST_QUERY_POSITION:{
767 gst_query_parse_position (query, &fmt, NULL);
768 if (fmt == GST_FORMAT_TIME
769 && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
770 gst_query_set_position (query, GST_FORMAT_TIME,
771 qtdemux->segment.position);
776 case GST_QUERY_DURATION:{
779 gst_query_parse_duration (query, &fmt, NULL);
780 if (fmt == GST_FORMAT_TIME) {
781 /* First try to query upstream */
782 res = gst_pad_query_default (pad, parent, query);
785 if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
786 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
793 case GST_QUERY_CONVERT:{
794 GstFormat src_fmt, dest_fmt;
795 gint64 src_value, dest_value = 0;
797 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
799 res = gst_qtdemux_src_convert (pad,
800 src_fmt, src_value, dest_fmt, &dest_value);
802 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
807 case GST_QUERY_FORMATS:
808 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
811 case GST_QUERY_SEEKING:{
815 /* try upstream first */
816 res = gst_pad_query_default (pad, parent, query);
819 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
820 if (fmt == GST_FORMAT_TIME) {
821 GstClockTime duration = GST_CLOCK_TIME_NONE;
823 gst_qtdemux_get_duration (qtdemux, &duration);
825 if (!qtdemux->pullbased) {
828 /* we might be able with help from upstream */
830 q = gst_query_new_seeking (GST_FORMAT_BYTES);
831 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
832 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
833 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
837 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
843 case GST_QUERY_SEGMENT:
848 format = qtdemux->segment.format;
851 gst_segment_to_stream_time (&qtdemux->segment, format,
852 qtdemux->segment.start);
853 if ((stop = qtdemux->segment.stop) == -1)
854 stop = qtdemux->segment.duration;
856 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
858 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
863 res = gst_pad_query_default (pad, parent, query);
871 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
873 if (G_LIKELY (stream->pad)) {
874 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
875 GST_DEBUG_PAD_NAME (stream->pad));
877 if (G_UNLIKELY (stream->pending_tags)) {
878 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
879 stream->pending_tags);
880 gst_pad_push_event (stream->pad,
881 gst_event_new_tag (stream->pending_tags));
882 stream->pending_tags = NULL;
885 if (G_UNLIKELY (stream->send_global_tags && qtdemux->tag_list)) {
886 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
888 gst_pad_push_event (stream->pad,
889 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
890 stream->send_global_tags = FALSE;
895 /* push event on all source pads; takes ownership of the event */
897 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
900 gboolean has_valid_stream = FALSE;
901 GstEventType etype = GST_EVENT_TYPE (event);
903 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
904 GST_EVENT_TYPE_NAME (event));
906 for (n = 0; n < qtdemux->n_streams; n++) {
908 QtDemuxStream *stream = qtdemux->streams[n];
909 GST_DEBUG_OBJECT (qtdemux, "pushing on pad %i", n);
911 if ((pad = stream->pad)) {
912 has_valid_stream = TRUE;
914 if (etype == GST_EVENT_EOS) {
915 /* let's not send twice */
916 if (stream->sent_eos)
918 stream->sent_eos = TRUE;
921 gst_pad_push_event (pad, gst_event_ref (event));
925 gst_event_unref (event);
927 /* if it is EOS and there are no pads, post an error */
928 if (!has_valid_stream && etype == GST_EVENT_EOS) {
929 gst_qtdemux_post_no_playable_stream_error (qtdemux);
933 /* push a pending newsegment event, if any from the streaming thread */
935 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
937 if (qtdemux->pending_newsegment) {
938 gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
939 qtdemux->pending_newsegment = NULL;
949 find_func (QtDemuxSample * s1, guint64 * media_time, gpointer user_data)
951 if (s1->timestamp + s1->pts_offset > *media_time)
957 /* find the index of the sample that includes the data for @media_time using a
958 * binary search. Only to be called in optimized cases of linear search below.
960 * Returns the index of the sample.
963 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
966 QtDemuxSample *result;
969 /* convert media_time to mov format */
971 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
973 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
974 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
975 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
977 if (G_LIKELY (result))
978 index = result - str->samples;
987 /* find the index of the sample that includes the data for @media_offset using a
990 * Returns the index of the sample.
993 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
994 QtDemuxStream * str, gint64 media_offset)
996 QtDemuxSample *result = str->samples;
999 if (result == NULL || str->n_samples == 0)
1002 if (media_offset == result->offset)
1006 while (index < str->n_samples - 1) {
1007 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1010 if (media_offset < result->offset)
1021 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1026 /* find the index of the sample that includes the data for @media_time using a
1027 * linear search, and keeping in mind that not all samples may have been parsed
1028 * yet. If possible, it will delegate to binary search.
1030 * Returns the index of the sample.
1033 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
1034 GstClockTime media_time)
1038 QtDemuxSample *sample;
1040 /* convert media_time to mov format */
1042 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1044 sample = str->samples;
1045 if (mov_time == sample->timestamp + sample->pts_offset)
1048 /* use faster search if requested time in already parsed range */
1049 sample = str->samples + str->stbl_index;
1050 if (str->stbl_index >= 0 &&
1051 mov_time <= (sample->timestamp + sample->pts_offset))
1052 return gst_qtdemux_find_index (qtdemux, str, media_time);
1054 while (index < str->n_samples - 1) {
1055 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1058 sample = str->samples + index + 1;
1059 if (mov_time < (sample->timestamp + sample->pts_offset))
1069 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1074 /* find the index of the keyframe needed to decode the sample at @index
1077 * Returns the index of the keyframe.
1080 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1083 guint32 new_index = index;
1085 if (index >= str->n_samples) {
1086 new_index = str->n_samples;
1090 /* all keyframes, return index */
1091 if (str->all_keyframe) {
1096 /* else go back until we have a keyframe */
1098 if (str->samples[new_index].keyframe)
1108 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index before index %u "
1109 "gave %u", index, new_index);
1114 /* find the segment for @time_position for @stream
1116 * Returns the index of the segment containing @time_position.
1117 * Returns the last segment and sets the @eos variable to TRUE
1118 * if the time is beyond the end. @eos may be NULL
1121 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1122 GstClockTime time_position)
1127 GST_LOG_OBJECT (qtdemux, "finding segment for %" GST_TIME_FORMAT,
1128 GST_TIME_ARGS (time_position));
1131 for (i = 0; i < stream->n_segments; i++) {
1132 QtDemuxSegment *segment = &stream->segments[i];
1134 GST_LOG_OBJECT (qtdemux,
1135 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1136 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1138 /* For the last segment we include stop_time in the last segment */
1139 if (i < stream->n_segments - 1) {
1140 if (segment->time <= time_position && time_position < segment->stop_time) {
1141 GST_LOG_OBJECT (qtdemux, "segment %d matches", i);
1146 /* Last segment always matches */
1154 /* move the stream @str to the sample position @index.
1156 * Updates @str->sample_index and marks discontinuity if needed.
1159 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1162 /* no change needed */
1163 if (index == str->sample_index)
1166 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1169 /* position changed, we have a discont */
1170 str->sample_index = index;
1171 str->offset_in_sample = 0;
1172 /* Each time we move in the stream we store the position where we are
1174 str->from_sample = index;
1175 str->discont = TRUE;
1179 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1180 gint64 * key_time, gint64 * key_offset)
1183 gint64 min_byte_offset = -1;
1186 min_offset = desired_time;
1188 /* for each stream, find the index of the sample in the segment
1189 * and move back to the previous keyframe. */
1190 for (n = 0; n < qtdemux->n_streams; n++) {
1192 guint32 index, kindex;
1194 GstClockTime media_start;
1195 GstClockTime media_time;
1196 GstClockTime seg_time;
1197 QtDemuxSegment *seg;
1199 str = qtdemux->streams[n];
1201 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1202 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1204 /* get segment and time in the segment */
1205 seg = &str->segments[seg_idx];
1206 seg_time = desired_time - seg->time;
1208 /* get the media time in the segment */
1209 media_start = seg->media_start + seg_time;
1211 /* get the index of the sample with media time */
1212 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1213 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1214 " at offset %" G_GUINT64_FORMAT,
1215 GST_TIME_ARGS (media_start), index, str->samples[index].offset);
1217 /* find previous keyframe */
1218 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index);
1220 /* if the keyframe is at a different position, we need to update the
1221 * requested seek time */
1222 if (index != kindex) {
1225 /* get timestamp of keyframe */
1226 media_time = QTSAMPLE_DTS (str, &str->samples[kindex]);
1227 GST_DEBUG_OBJECT (qtdemux,
1228 "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1229 G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1230 str->samples[kindex].offset);
1232 /* keyframes in the segment get a chance to change the
1233 * desired_offset. keyframes out of the segment are
1235 if (media_time >= seg->media_start) {
1236 GstClockTime seg_time;
1238 /* this keyframe is inside the segment, convert back to
1240 seg_time = (media_time - seg->media_start) + seg->time;
1241 if (seg_time < min_offset)
1242 min_offset = seg_time;
1246 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1247 min_byte_offset = str->samples[index].offset;
1251 *key_time = min_offset;
1253 *key_offset = min_byte_offset;
1257 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1258 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1262 g_return_val_if_fail (format != NULL, FALSE);
1263 g_return_val_if_fail (cur != NULL, FALSE);
1264 g_return_val_if_fail (stop != NULL, FALSE);
1266 if (*format == GST_FORMAT_TIME)
1270 if (cur_type != GST_SEEK_TYPE_NONE)
1271 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1272 if (res && stop_type != GST_SEEK_TYPE_NONE)
1273 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1276 *format = GST_FORMAT_TIME;
1281 /* perform seek in push based mode:
1282 find BYTE position to move to based on time and delegate to upstream
1285 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1290 GstSeekType cur_type, stop_type;
1291 gint64 cur, stop, key_cur;
1294 gint64 original_stop;
1297 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1299 gst_event_parse_seek (event, &rate, &format, &flags,
1300 &cur_type, &cur, &stop_type, &stop);
1301 seqnum = gst_event_get_seqnum (event);
1303 /* only forward streaming and seeking is possible */
1305 goto unsupported_seek;
1307 /* convert to TIME if needed and possible */
1308 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1312 /* Upstrea seek in bytes will have undefined stop, but qtdemux stores
1313 * the original stop position to use when upstream pushes the new segment
1315 original_stop = stop;
1318 /* find reasonable corresponding BYTE position,
1319 * also try to mind about keyframes, since we can not go back a bit for them
1321 gst_qtdemux_adjust_seek (qtdemux, cur, &key_cur, &byte_cur);
1326 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1327 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1330 GST_OBJECT_LOCK (qtdemux);
1331 qtdemux->seek_offset = byte_cur;
1332 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1333 qtdemux->push_seek_start = cur;
1335 qtdemux->push_seek_start = key_cur;
1338 if (stop_type == GST_SEEK_TYPE_NONE) {
1339 qtdemux->push_seek_stop = qtdemux->segment.stop;
1341 qtdemux->push_seek_stop = original_stop;
1343 GST_OBJECT_UNLOCK (qtdemux);
1345 /* BYTE seek event */
1346 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1348 gst_event_set_seqnum (event, seqnum);
1349 res = gst_pad_push_event (qtdemux->sinkpad, event);
1356 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1362 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1367 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1372 /* perform the seek.
1374 * We set all segment_indexes in the streams to unknown and
1375 * adjust the time_position to the desired position. this is enough
1376 * to trigger a segment switch in the streaming thread to start
1377 * streaming from the desired position.
1379 * Keyframe seeking is a little more complicated when dealing with
1380 * segments. Ideally we want to move to the previous keyframe in
1381 * the segment but there might not be a keyframe in the segment. In
1382 * fact, none of the segments could contain a keyframe. We take a
1383 * practical approach: seek to the previous keyframe in the segment,
1384 * if there is none, seek to the beginning of the segment.
1386 * Called with STREAM_LOCK
1389 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1392 gint64 desired_offset;
1395 desired_offset = segment->position;
1397 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1398 GST_TIME_ARGS (desired_offset));
1400 /* may not have enough fragmented info to do this adjustment,
1401 * and we can't scan (and probably should not) at this time with
1402 * possibly flushing upstream */
1403 if ((segment->flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1406 gst_qtdemux_adjust_seek (qtdemux, desired_offset, &min_offset, NULL);
1407 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1408 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1409 desired_offset = min_offset;
1412 /* and set all streams to the final position */
1413 for (n = 0; n < qtdemux->n_streams; n++) {
1414 QtDemuxStream *stream = qtdemux->streams[n];
1416 stream->time_position = desired_offset;
1417 stream->sample_index = -1;
1418 stream->offset_in_sample = 0;
1419 stream->segment_index = -1;
1420 stream->sent_eos = FALSE;
1421 stream->segment_seqnum = seqnum;
1423 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1424 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1426 segment->position = desired_offset;
1427 segment->time = desired_offset;
1428 qtdemux->segment_base = desired_offset;
1430 /* we stop at the end */
1431 if (segment->stop == -1)
1432 segment->stop = segment->duration;
1434 if (qtdemux->fragmented)
1435 qtdemux->fragmented_seek_pending = TRUE;
1440 /* do a seek in pull based mode */
1442 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1447 GstSeekType cur_type, stop_type;
1451 GstSegment seeksegment;
1453 GstEvent *flush_event;
1456 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1458 gst_event_parse_seek (event, &rate, &format, &flags,
1459 &cur_type, &cur, &stop_type, &stop);
1460 seqnum = gst_event_get_seqnum (event);
1462 /* we have to have a format as the segment format. Try to convert
1464 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1468 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1470 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1474 flush = flags & GST_SEEK_FLAG_FLUSH;
1476 /* stop streaming, either by flushing or by pausing the task */
1478 flush_event = gst_event_new_flush_start ();
1480 gst_event_set_seqnum (flush_event, seqnum);
1481 /* unlock upstream pull_range */
1482 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1483 /* make sure out loop function exits */
1484 gst_qtdemux_push_event (qtdemux, flush_event);
1486 /* non flushing seek, pause the task */
1487 gst_pad_pause_task (qtdemux->sinkpad);
1490 /* wait for streaming to finish */
1491 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1493 /* copy segment, we need this because we still need the old
1494 * segment when we close the current segment. */
1495 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1498 /* configure the segment with the seek variables */
1499 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1500 gst_segment_do_seek (&seeksegment, rate, format, flags,
1501 cur_type, cur, stop_type, stop, &update);
1504 /* now do the seek, this actually never returns FALSE */
1505 gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum);
1507 /* prepare for streaming again */
1509 flush_event = gst_event_new_flush_stop (TRUE);
1511 gst_event_set_seqnum (flush_event, seqnum);
1513 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1514 gst_qtdemux_push_event (qtdemux, flush_event);
1517 /* commit the new segment */
1518 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1520 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1521 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1522 qtdemux->segment.format, qtdemux->segment.position);
1524 gst_message_set_seqnum (msg, seqnum);
1525 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1528 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1529 qtdemux->sinkpad, NULL);
1531 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1538 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1544 qtdemux_ensure_index (GstQTDemux * qtdemux)
1548 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1550 /* Build complete index */
1551 for (i = 0; i < qtdemux->n_streams; i++) {
1552 QtDemuxStream *stream = qtdemux->streams[i];
1554 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1562 GST_LOG_OBJECT (qtdemux,
1563 "Building complete index of stream %u for seeking failed!", i);
1569 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1572 gboolean res = TRUE;
1573 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1575 switch (GST_EVENT_TYPE (event)) {
1576 case GST_EVENT_SEEK:
1578 #ifndef GST_DISABLE_GST_DEBUG
1579 GstClockTime ts = gst_util_get_timestamp ();
1582 if (qtdemux->upstream_newsegment && qtdemux->fragmented) {
1583 /* seek should be handled by upstream, we might need to re-download fragments */
1584 GST_DEBUG_OBJECT (qtdemux,
1585 "let upstream handle seek for fragmented playback");
1589 /* Build complete index for seeking;
1590 * if not a fragmented file at least */
1591 if (!qtdemux->fragmented)
1592 if (!qtdemux_ensure_index (qtdemux))
1594 #ifndef GST_DISABLE_GST_DEBUG
1595 ts = gst_util_get_timestamp () - ts;
1596 GST_INFO_OBJECT (qtdemux,
1597 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1600 if (qtdemux->pullbased) {
1601 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1602 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1603 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1605 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams
1606 && !qtdemux->fragmented) {
1607 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1609 GST_DEBUG_OBJECT (qtdemux,
1610 "ignoring seek in push mode in current state");
1613 gst_event_unref (event);
1616 case GST_EVENT_NAVIGATION:
1618 gst_event_unref (event);
1622 res = gst_pad_event_default (pad, parent, event);
1632 GST_ERROR_OBJECT (qtdemux, "Index failed");
1633 gst_event_unref (event);
1639 /* stream/index return sample that is min/max w.r.t. byte position,
1640 * time is min/max w.r.t. time of samples,
1641 * the latter need not be time of the former sample */
1643 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1644 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1647 gint64 time, min_time;
1648 QtDemuxStream *stream;
1654 for (n = 0; n < qtdemux->n_streams; ++n) {
1657 gboolean set_sample;
1659 str = qtdemux->streams[n];
1666 i = str->n_samples - 1;
1670 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1671 if (str->samples[i].size == 0)
1674 if (fw && (str->samples[i].offset < byte_pos))
1677 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1680 /* move stream to first available sample */
1682 gst_qtdemux_move_stream (qtdemux, str, i);
1686 /* avoid index from sparse streams since they might be far away */
1688 /* determine min/max time */
1689 time = QTSAMPLE_PTS (str, &str->samples[i]);
1690 if (min_time == -1 || (!fw && time > min_time) ||
1691 (fw && time < min_time)) {
1695 /* determine stream with leading sample, to get its position */
1697 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1698 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1706 /* no sample for this stream, mark eos */
1708 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1719 static QtDemuxStream *
1720 _create_stream (void)
1722 QtDemuxStream *stream;
1724 stream = g_new0 (QtDemuxStream, 1);
1725 /* new streams always need a discont */
1726 stream->discont = TRUE;
1727 /* we enable clipping for raw audio/video streams */
1728 stream->need_clip = FALSE;
1729 stream->need_process = FALSE;
1730 stream->segment_index = -1;
1731 stream->time_position = 0;
1732 stream->sample_index = -1;
1733 stream->offset_in_sample = 0;
1734 stream->new_stream = TRUE;
1739 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1741 GstStructure *structure;
1742 const gchar *variant;
1743 const GstCaps *mediacaps = NULL;
1745 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1747 structure = gst_caps_get_structure (caps, 0);
1748 variant = gst_structure_get_string (structure, "variant");
1750 if (variant && strcmp (variant, "mss-fragmented") == 0) {
1751 QtDemuxStream *stream;
1752 const GValue *value;
1754 demux->fragmented = TRUE;
1755 demux->mss_mode = TRUE;
1757 if (demux->n_streams > 1) {
1758 /* can't do this, we can only renegotiate for another mss format */
1762 value = gst_structure_get_value (structure, "media-caps");
1765 const GValue *timescale_v;
1767 /* TODO update when stream changes during playback */
1769 if (demux->n_streams == 0) {
1770 stream = _create_stream ();
1771 demux->streams[demux->n_streams] = stream;
1772 demux->n_streams = 1;
1774 stream = demux->streams[0];
1777 timescale_v = gst_structure_get_value (structure, "timescale");
1779 stream->timescale = g_value_get_uint64 (timescale_v);
1781 /* default mss timescale */
1782 stream->timescale = 10000000;
1784 demux->timescale = stream->timescale;
1786 mediacaps = gst_value_get_caps (value);
1787 if (!stream->caps || !gst_caps_is_equal_fixed (mediacaps, stream->caps)) {
1788 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1790 stream->new_caps = TRUE;
1792 gst_caps_replace (&stream->caps, (GstCaps *) mediacaps);
1793 structure = gst_caps_get_structure (mediacaps, 0);
1794 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
1795 stream->subtype = FOURCC_vide;
1797 gst_structure_get_int (structure, "width", &stream->width);
1798 gst_structure_get_int (structure, "height", &stream->height);
1799 gst_structure_get_fraction (structure, "framerate", &stream->fps_n,
1801 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
1803 stream->subtype = FOURCC_soun;
1804 gst_structure_get_int (structure, "channels", &stream->n_channels);
1805 gst_structure_get_int (structure, "rate", &rate);
1806 stream->rate = rate;
1809 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
1811 demux->mss_mode = FALSE;
1818 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
1822 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
1823 gst_pad_stop_task (qtdemux->sinkpad);
1825 if (hard || qtdemux->upstream_newsegment) {
1826 qtdemux->state = QTDEMUX_STATE_INITIAL;
1827 qtdemux->neededbytes = 16;
1828 qtdemux->todrop = 0;
1829 qtdemux->pullbased = FALSE;
1830 qtdemux->posted_redirect = FALSE;
1831 qtdemux->first_mdat = -1;
1832 qtdemux->header_size = 0;
1833 qtdemux->mdatoffset = -1;
1834 qtdemux->restoredata_offset = -1;
1835 if (qtdemux->mdatbuffer)
1836 gst_buffer_unref (qtdemux->mdatbuffer);
1837 if (qtdemux->restoredata_buffer)
1838 gst_buffer_unref (qtdemux->restoredata_buffer);
1839 qtdemux->mdatbuffer = NULL;
1840 qtdemux->restoredata_buffer = NULL;
1841 qtdemux->mdatleft = 0;
1842 if (qtdemux->comp_brands)
1843 gst_buffer_unref (qtdemux->comp_brands);
1844 qtdemux->comp_brands = NULL;
1845 qtdemux->last_moov_offset = -1;
1846 if (qtdemux->moov_node)
1847 g_node_destroy (qtdemux->moov_node);
1848 qtdemux->moov_node = NULL;
1849 qtdemux->moov_node_compressed = NULL;
1850 if (qtdemux->tag_list)
1851 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
1852 qtdemux->tag_list = NULL;
1854 if (qtdemux->element_index)
1855 gst_object_unref (qtdemux->element_index);
1856 qtdemux->element_index = NULL;
1858 qtdemux->major_brand = 0;
1859 if (qtdemux->pending_newsegment)
1860 gst_event_unref (qtdemux->pending_newsegment);
1861 qtdemux->pending_newsegment = NULL;
1862 qtdemux->upstream_newsegment = FALSE;
1863 qtdemux->upstream_seekable = FALSE;
1864 qtdemux->upstream_size = 0;
1866 qtdemux->fragment_start = -1;
1867 qtdemux->fragment_start_offset = -1;
1868 qtdemux->duration = 0;
1869 qtdemux->moof_offset = 0;
1870 qtdemux->chapters_track_id = 0;
1871 qtdemux->have_group_id = FALSE;
1872 qtdemux->group_id = G_MAXUINT;
1874 qtdemux->offset = 0;
1875 gst_adapter_clear (qtdemux->adapter);
1876 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
1877 qtdemux->segment_base = 0;
1880 for (n = 0; n < qtdemux->n_streams; n++) {
1881 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
1882 qtdemux->streams[n] = NULL;
1884 qtdemux->n_streams = 0;
1885 qtdemux->n_video_streams = 0;
1886 qtdemux->n_audio_streams = 0;
1887 qtdemux->n_sub_streams = 0;
1888 qtdemux->exposed = FALSE;
1889 qtdemux->fragmented = FALSE;
1890 qtdemux->mss_mode = FALSE;
1891 gst_caps_replace (&qtdemux->media_caps, NULL);
1892 qtdemux->timescale = 0;
1893 qtdemux->got_moov = FALSE;
1894 } else if (qtdemux->mss_mode) {
1895 for (n = 0; n < qtdemux->n_streams; n++)
1896 gst_qtdemux_stream_clear (qtdemux, qtdemux->streams[n]);
1898 for (n = 0; n < qtdemux->n_streams; n++) {
1899 qtdemux->streams[n]->sent_eos = FALSE;
1900 qtdemux->streams[n]->segment_seqnum = 0;
1901 qtdemux->streams[n]->time_position = 0;
1907 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
1910 GstQTDemux *demux = GST_QTDEMUX (parent);
1911 gboolean res = TRUE;
1913 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
1915 switch (GST_EVENT_TYPE (event)) {
1916 case GST_EVENT_SEGMENT:
1919 QtDemuxStream *stream;
1922 GstEvent *segment_event;
1924 /* some debug output */
1925 gst_event_copy_segment (event, &segment);
1926 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
1929 if (segment.format == GST_FORMAT_TIME) {
1930 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
1931 gst_event_replace (&demux->pending_newsegment, event);
1932 demux->upstream_newsegment = TRUE;
1934 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
1935 "not in time format");
1937 /* chain will send initial newsegment after pads have been added */
1938 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
1939 GST_DEBUG_OBJECT (demux, "still starting, eating event");
1944 /* check if this matches a time seek we received previously
1945 * FIXME for backwards compatibility reasons we use the
1946 * seek_offset here to compare. In the future we might want to
1947 * change this to use the seqnum as it uniquely should identify
1948 * the segment that corresponds to the seek. */
1949 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
1950 ", received segment offset %" G_GINT64_FORMAT,
1951 demux->seek_offset, segment.start);
1952 if (segment.format == GST_FORMAT_BYTES
1953 && demux->seek_offset == segment.start) {
1954 GST_OBJECT_LOCK (demux);
1955 offset = segment.start;
1957 segment.format = GST_FORMAT_TIME;
1958 segment.start = demux->push_seek_start;
1959 segment.stop = demux->push_seek_stop;
1960 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
1961 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
1962 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
1963 GST_OBJECT_UNLOCK (demux);
1966 /* we only expect a BYTE segment, e.g. following a seek */
1967 if (segment.format == GST_FORMAT_BYTES) {
1968 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
1969 offset = segment.start;
1971 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
1972 NULL, (gint64 *) & segment.start);
1973 if ((gint64) segment.start < 0)
1976 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
1977 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
1978 NULL, (gint64 *) & segment.stop);
1979 /* keyframe seeking should already arrange for start >= stop,
1980 * but make sure in other rare cases */
1981 segment.stop = MAX (segment.stop, segment.start);
1983 } else if (segment.format == GST_FORMAT_TIME) {
1986 gst_qtdemux_push_event (demux, gst_event_ref (event));
1987 gst_event_new_new_segment_full (segment.update, segment.rate,
1988 segment.arate, GST_FORMAT_TIME, segment.start, segment.stop,
1990 gst_adapter_clear (demux->adapter);
1991 demux->neededbytes = 16;
1995 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
1999 /* accept upstream's notion of segment and distribute along */
2000 segment.format = GST_FORMAT_TIME;
2001 segment.position = segment.time = segment.start;
2002 segment.duration = demux->segment.duration;
2003 segment.base = gst_segment_to_running_time (&demux->segment,
2004 GST_FORMAT_TIME, demux->segment.position);
2006 gst_segment_copy_into (&segment, &demux->segment);
2007 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2008 segment_event = gst_event_new_segment (&segment);
2009 gst_event_set_seqnum (segment_event, gst_event_get_seqnum (event));
2010 gst_qtdemux_push_event (demux, segment_event);
2012 /* clear leftover in current segment, if any */
2013 gst_adapter_clear (demux->adapter);
2014 /* set up streaming thread */
2015 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx, NULL);
2016 demux->offset = offset;
2018 demux->todrop = stream->samples[idx].offset - offset;
2019 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2021 /* set up for EOS */
2022 if (demux->upstream_newsegment) {
2023 demux->neededbytes = 16;
2025 demux->neededbytes = -1;
2030 gst_event_unref (event);
2034 case GST_EVENT_FLUSH_STOP:
2038 dur = demux->segment.duration;
2039 gst_qtdemux_reset (demux, FALSE);
2040 demux->segment.duration = dur;
2044 /* If we are in push mode, and get an EOS before we've seen any streams,
2045 * then error out - we have nowhere to send the EOS */
2046 if (!demux->pullbased) {
2048 gboolean has_valid_stream = FALSE;
2049 for (i = 0; i < demux->n_streams; i++) {
2050 if (demux->streams[i]->pad != NULL) {
2051 has_valid_stream = TRUE;
2055 if (!has_valid_stream)
2056 gst_qtdemux_post_no_playable_stream_error (demux);
2058 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2059 (guint) gst_adapter_available (demux->adapter));
2060 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2066 case GST_EVENT_CAPS:{
2067 GstCaps *caps = NULL;
2069 gst_event_parse_caps (event, &caps);
2070 gst_qtdemux_setcaps (demux, caps);
2072 gst_event_unref (event);
2079 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2087 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2089 GstQTDemux *demux = GST_QTDEMUX (element);
2091 GST_OBJECT_LOCK (demux);
2092 if (demux->element_index)
2093 gst_object_unref (demux->element_index);
2095 demux->element_index = gst_object_ref (index);
2097 demux->element_index = NULL;
2099 GST_OBJECT_UNLOCK (demux);
2100 /* object lock might be taken again */
2102 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2103 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2104 demux->element_index, demux->index_id);
2108 gst_qtdemux_get_index (GstElement * element)
2110 GstIndex *result = NULL;
2111 GstQTDemux *demux = GST_QTDEMUX (element);
2113 GST_OBJECT_LOCK (demux);
2114 if (demux->element_index)
2115 result = gst_object_ref (demux->element_index);
2116 GST_OBJECT_UNLOCK (demux);
2118 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2125 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2127 g_free ((gpointer) stream->stco.data);
2128 stream->stco.data = NULL;
2129 g_free ((gpointer) stream->stsz.data);
2130 stream->stsz.data = NULL;
2131 g_free ((gpointer) stream->stsc.data);
2132 stream->stsc.data = NULL;
2133 g_free ((gpointer) stream->stts.data);
2134 stream->stts.data = NULL;
2135 g_free ((gpointer) stream->stss.data);
2136 stream->stss.data = NULL;
2137 g_free ((gpointer) stream->stps.data);
2138 stream->stps.data = NULL;
2139 g_free ((gpointer) stream->ctts.data);
2140 stream->ctts.data = NULL;
2144 gst_qtdemux_stream_clear (GstQTDemux * qtdemux, QtDemuxStream * stream)
2146 if (stream->allocator)
2147 gst_object_unref (stream->allocator);
2148 while (stream->buffers) {
2149 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2150 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2152 if (stream->rgb8_palette) {
2153 gst_memory_unref (stream->rgb8_palette);
2154 stream->rgb8_palette = NULL;
2156 g_free (stream->samples);
2157 stream->samples = NULL;
2158 g_free (stream->segments);
2159 stream->segments = NULL;
2160 if (stream->pending_tags)
2161 gst_tag_list_unref (stream->pending_tags);
2162 stream->pending_tags = NULL;
2163 g_free (stream->redirect_uri);
2164 stream->redirect_uri = NULL;
2165 /* free stbl sub-atoms */
2166 gst_qtdemux_stbl_free (stream);
2168 g_free (stream->ra_entries);
2169 stream->ra_entries = NULL;
2170 stream->n_ra_entries = 0;
2172 stream->sent_eos = FALSE;
2173 stream->segment_index = -1;
2174 stream->time_position = 0;
2175 stream->sample_index = -1;
2176 stream->stbl_index = -1;
2177 stream->n_samples = 0;
2178 stream->sparse = FALSE;
2182 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
2184 gst_qtdemux_stream_clear (qtdemux, stream);
2186 gst_caps_unref (stream->caps);
2187 stream->caps = NULL;
2189 gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
2190 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, stream->pad);
2196 gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int i)
2198 g_assert (i >= 0 && i < qtdemux->n_streams && qtdemux->streams[i] != NULL);
2200 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[i]);
2201 qtdemux->streams[i] = qtdemux->streams[qtdemux->n_streams - 1];
2202 qtdemux->streams[qtdemux->n_streams - 1] = NULL;
2203 qtdemux->n_streams--;
2206 static GstStateChangeReturn
2207 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2209 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2210 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2212 switch (transition) {
2213 case GST_STATE_CHANGE_PAUSED_TO_READY:
2219 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2221 switch (transition) {
2222 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2223 gst_qtdemux_reset (qtdemux, TRUE);
2234 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2236 /* counts as header data */
2237 qtdemux->header_size += length;
2239 /* only consider at least a sufficiently complete ftyp atom */
2243 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2244 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2245 GST_FOURCC_ARGS (qtdemux->major_brand));
2246 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2247 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2252 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist)
2254 /* Strip out bogus fields */
2256 gst_tag_list_remove_tag (taglist, GST_TAG_VIDEO_CODEC);
2258 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, taglist);
2260 if (qtdemux->tag_list) {
2261 /* prioritize native tags using _KEEP mode */
2262 gst_tag_list_insert (qtdemux->tag_list, taglist, GST_TAG_MERGE_KEEP);
2263 gst_tag_list_unref (taglist);
2265 qtdemux->tag_list = taglist;
2270 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2272 static guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2273 0x97, 0xA9, 0x42, 0xE8,
2274 0x9C, 0x71, 0x99, 0x94,
2275 0x91, 0xE3, 0xAF, 0xAC
2277 static guint8 playready_uuid[] = {
2278 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2279 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2283 /* counts as header data */
2284 qtdemux->header_size += length;
2286 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2288 if (length <= offset + 16) {
2289 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2293 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2295 GstTagList *taglist;
2297 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2298 length - offset - 16, NULL);
2299 taglist = gst_tag_list_from_xmp_buffer (buf);
2300 gst_buffer_unref (buf);
2302 qtdemux_handle_xmp_taglist (qtdemux, taglist);
2304 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
2306 const gunichar2 *s_utf16;
2309 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
2310 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
2311 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
2312 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
2316 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
2317 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
2320 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
2321 GST_READ_UINT32_LE (buffer + offset),
2322 GST_READ_UINT32_LE (buffer + offset + 4),
2323 GST_READ_UINT32_LE (buffer + offset + 8),
2324 GST_READ_UINT32_LE (buffer + offset + 12));
2328 /* caller verifies at least 8 bytes in buf */
2330 extract_initial_length_and_fourcc (const guint8 * data, guint size,
2331 guint64 * plength, guint32 * pfourcc)
2336 length = QT_UINT32 (data);
2337 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2338 fourcc = QT_FOURCC (data + 4);
2339 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
2342 length = G_MAXUINT32;
2343 } else if (length == 1 && size >= 16) {
2344 /* this means we have an extended size, which is the 64 bit value of
2345 * the next 8 bytes */
2346 length = QT_UINT64 (data + 8);
2347 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2357 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
2359 guint32 version = 0;
2360 GstClockTime duration = 0;
2362 if (!gst_byte_reader_get_uint32_be (br, &version))
2367 if (!gst_byte_reader_get_uint64_be (br, &duration))
2372 if (!gst_byte_reader_get_uint32_be (br, &dur))
2377 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
2378 qtdemux->duration = duration;
2384 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
2390 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
2391 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
2393 if (!stream->parsed_trex && qtdemux->moov_node) {
2395 GstByteReader trex_data;
2397 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
2399 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
2402 guint32 id = 0, dur = 0, size = 0, flags = 0, dummy = 0;
2404 /* skip version/flags */
2405 if (!gst_byte_reader_skip (&trex_data, 4))
2407 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
2409 if (id != stream->track_id)
2411 /* sample description index; ignore */
2412 if (!gst_byte_reader_get_uint32_be (&trex_data, &dummy))
2414 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2416 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
2418 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
2421 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
2422 "duration %d, size %d, flags 0x%x", stream->track_id,
2425 stream->parsed_trex = TRUE;
2426 stream->def_sample_duration = dur;
2427 stream->def_sample_size = size;
2428 stream->def_sample_flags = flags;
2431 /* iterate all siblings */
2432 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
2438 *ds_duration = stream->def_sample_duration;
2439 *ds_size = stream->def_sample_size;
2440 *ds_flags = stream->def_sample_flags;
2442 /* even then, above values are better than random ... */
2443 if (G_UNLIKELY (!stream->parsed_trex)) {
2444 GST_WARNING_OBJECT (qtdemux,
2445 "failed to find fragment defaults for stream %d", stream->track_id);
2452 /* This method should be called whenever a more accurate duration might
2453 * have been found. It will update all relevant variables if/where needed
2456 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
2460 GstClockTime prevdur;
2462 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
2464 if (movdur > qtdemux->duration) {
2465 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
2466 GST_DEBUG_OBJECT (qtdemux,
2467 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
2468 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
2469 qtdemux->duration = movdur;
2470 GST_DEBUG_OBJECT (qtdemux,
2471 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
2472 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
2473 GST_TIME_ARGS (qtdemux->segment.stop));
2474 if (qtdemux->segment.duration == prevdur) {
2475 /* If the current segment has duration/stop identical to previous duration
2476 * update them also (because they were set at that point in time with
2477 * the wrong duration */
2478 /* We convert the value *from* the timescale version to avoid rounding errors */
2479 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
2480 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
2481 qtdemux->segment.duration = fixeddur;
2482 qtdemux->segment.stop = fixeddur;
2485 for (i = 0; i < qtdemux->n_streams; i++) {
2486 QtDemuxStream *stream = qtdemux->streams[i];
2488 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
2489 if (movdur > stream->duration) {
2490 GST_DEBUG_OBJECT (qtdemux,
2491 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
2492 GST_TIME_ARGS (duration));
2493 stream->duration = movdur;
2494 if (stream->dummy_segment) {
2495 /* Update all dummy values to new duration */
2496 stream->segments[0].stop_time = duration;
2497 stream->segments[0].duration = duration;
2498 stream->segments[0].media_stop = duration;
2506 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
2507 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
2508 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
2509 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts)
2511 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
2513 gint32 data_offset = 0;
2514 guint32 flags = 0, first_flags = 0, samples_count = 0;
2517 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
2518 QtDemuxSample *sample;
2519 gboolean ismv = FALSE;
2521 GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
2522 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
2523 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
2524 d_sample_size, d_sample_flags, *base_offset, decode_ts);
2526 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
2527 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
2531 /* presence of stss or not can't really tell us much,
2532 * and flags and so on tend to be marginally reliable in these files */
2533 if (stream->subtype == FOURCC_soun) {
2534 GST_DEBUG_OBJECT (qtdemux,
2535 "sound track in fragmented file; marking all keyframes");
2536 stream->all_keyframe = TRUE;
2539 if (!gst_byte_reader_skip (trun, 1) ||
2540 !gst_byte_reader_get_uint24_be (trun, &flags))
2543 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
2546 if (flags & TR_DATA_OFFSET) {
2547 /* note this is really signed */
2548 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
2550 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
2551 /* default base offset = first byte of moof */
2552 if (*base_offset == -1) {
2553 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
2554 *base_offset = moof_offset;
2556 *running_offset = *base_offset + data_offset;
2558 /* if no offset at all, that would mean data starts at moof start,
2559 * which is a bit wrong and is ismv crappy way, so compensate
2560 * assuming data is in mdat following moof */
2561 if (*base_offset == -1) {
2562 *base_offset = moof_offset + moof_length + 8;
2563 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
2566 if (*running_offset == -1)
2567 *running_offset = *base_offset;
2570 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
2572 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
2573 data_offset, flags, samples_count);
2575 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2576 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
2577 GST_DEBUG_OBJECT (qtdemux,
2578 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
2579 flags ^= TR_FIRST_SAMPLE_FLAGS;
2581 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
2583 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
2587 /* FIXME ? spec says other bits should also be checked to determine
2588 * entry size (and prefix size for that matter) */
2590 dur_offset = size_offset = 0;
2591 if (flags & TR_SAMPLE_DURATION) {
2592 GST_LOG_OBJECT (qtdemux, "entry duration present");
2593 dur_offset = entry_size;
2596 if (flags & TR_SAMPLE_SIZE) {
2597 GST_LOG_OBJECT (qtdemux, "entry size present");
2598 size_offset = entry_size;
2601 if (flags & TR_SAMPLE_FLAGS) {
2602 GST_LOG_OBJECT (qtdemux, "entry flags present");
2603 flags_offset = entry_size;
2606 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2607 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
2608 ct_offset = entry_size;
2612 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
2614 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
2616 if (stream->n_samples >=
2617 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
2620 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
2621 stream->n_samples, (guint) sizeof (QtDemuxSample),
2622 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
2624 /* create a new array of samples if it's the first sample parsed */
2625 if (stream->n_samples == 0)
2626 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
2627 /* or try to reallocate it with space enough to insert the new samples */
2629 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
2630 stream->n_samples + samples_count);
2631 if (stream->samples == NULL)
2634 if (qtdemux->fragment_start != -1) {
2635 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
2636 qtdemux->fragment_start = -1;
2638 if (G_UNLIKELY (stream->n_samples == 0)) {
2639 if (decode_ts > 0) {
2640 timestamp = decode_ts;
2641 } else if (stream->pending_seek != NULL) {
2642 /* if we don't have a timestamp from a tfdt box, we'll use the one
2643 * from the mfra seek table */
2644 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
2645 GST_TIME_ARGS (stream->pending_seek->ts));
2647 /* FIXME: this is not fully correct, the timestamp refers to the random
2648 * access sample refered to in the tfra entry, which may not necessarily
2649 * be the first sample in the tfrag/trun (but hopefully/usually is) */
2650 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
2655 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
2656 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
2657 GST_TIME_ARGS (gst_ts));
2659 /* subsequent fragments extend stream */
2661 stream->samples[stream->n_samples - 1].timestamp +
2662 stream->samples[stream->n_samples - 1].duration;
2664 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
2665 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
2666 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
2670 sample = stream->samples + stream->n_samples;
2671 for (i = 0; i < samples_count; i++) {
2672 guint32 dur, size, sflags, ct;
2674 /* first read sample data */
2675 if (flags & TR_SAMPLE_DURATION) {
2676 dur = QT_UINT32 (data + dur_offset);
2678 dur = d_sample_duration;
2680 if (flags & TR_SAMPLE_SIZE) {
2681 size = QT_UINT32 (data + size_offset);
2683 size = d_sample_size;
2685 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2687 sflags = first_flags;
2689 sflags = d_sample_flags;
2691 } else if (flags & TR_SAMPLE_FLAGS) {
2692 sflags = QT_UINT32 (data + flags_offset);
2694 sflags = d_sample_flags;
2696 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2697 ct = QT_UINT32 (data + ct_offset);
2703 /* fill the sample information */
2704 sample->offset = *running_offset;
2705 sample->pts_offset = ct;
2706 sample->size = size;
2707 sample->timestamp = timestamp;
2708 sample->duration = dur;
2709 /* sample-is-difference-sample */
2710 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
2711 * now idea how it relates to bitfield other than massive LE/BE confusion */
2712 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
2713 *running_offset += size;
2718 /* Update total duration if needed */
2719 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
2721 stream->n_samples += samples_count;
2723 if (stream->pending_seek != NULL)
2724 stream->pending_seek = NULL;
2730 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
2735 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
2741 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
2742 "be larger than %uMB (broken file?)", stream->n_samples,
2743 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
2748 /* find stream with @id */
2749 static inline QtDemuxStream *
2750 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
2752 QtDemuxStream *stream;
2756 if (G_UNLIKELY (!id)) {
2757 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
2761 /* try to get it fast and simple */
2762 if (G_LIKELY (id <= qtdemux->n_streams)) {
2763 stream = qtdemux->streams[id - 1];
2764 if (G_LIKELY (stream->track_id == id))
2768 /* linear search otherwise */
2769 for (i = 0; i < qtdemux->n_streams; i++) {
2770 stream = qtdemux->streams[i];
2771 if (stream->track_id == id)
2774 if (qtdemux->mss_mode) {
2775 /* mss should have only 1 stream anyway */
2776 return qtdemux->streams[0];
2783 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
2784 guint32 * fragment_number)
2786 if (!gst_byte_reader_skip (mfhd, 4))
2788 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
2793 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
2799 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
2800 QtDemuxStream ** stream, guint32 * default_sample_duration,
2801 guint32 * default_sample_size, guint32 * default_sample_flags,
2802 gint64 * base_offset)
2805 guint32 track_id = 0;
2807 if (!gst_byte_reader_skip (tfhd, 1) ||
2808 !gst_byte_reader_get_uint24_be (tfhd, &flags))
2811 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
2814 *stream = qtdemux_find_stream (qtdemux, track_id);
2815 if (G_UNLIKELY (!*stream))
2816 goto unknown_stream;
2818 if (flags & TF_BASE_DATA_OFFSET)
2819 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
2822 /* obtain stream defaults */
2823 qtdemux_parse_trex (qtdemux, *stream,
2824 default_sample_duration, default_sample_size, default_sample_flags);
2826 /* FIXME: Handle TF_SAMPLE_DESCRIPTION_INDEX properly */
2827 if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
2828 if (!gst_byte_reader_skip (tfhd, 4))
2831 if (flags & TF_DEFAULT_SAMPLE_DURATION)
2832 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
2835 if (flags & TF_DEFAULT_SAMPLE_SIZE)
2836 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
2839 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
2840 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
2847 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
2852 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
2858 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
2859 guint64 * decode_time)
2861 guint32 version = 0;
2863 if (!gst_byte_reader_get_uint32_be (br, &version))
2868 if (!gst_byte_reader_get_uint64_be (br, decode_time))
2871 guint32 dec_time = 0;
2872 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
2874 *decode_time = dec_time;
2877 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
2884 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
2890 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
2891 guint64 moof_offset, QtDemuxStream * stream)
2893 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
2894 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
2895 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
2896 gint64 base_offset, running_offset;
2899 /* NOTE @stream ignored */
2901 moof_node = g_node_new ((guint8 *) buffer);
2902 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
2903 qtdemux_node_dump (qtdemux, moof_node);
2905 /* Get fragment number from mfhd and check it's valid */
2907 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
2908 if (mfhd_node == NULL)
2910 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
2912 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
2914 /* unknown base_offset to start with */
2915 base_offset = running_offset = -1;
2916 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
2918 guint64 decode_time = 0;
2920 /* Fragment Header node */
2922 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
2926 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
2927 &ds_size, &ds_flags, &base_offset))
2930 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
2933 GstClockTime decode_time_ts;
2935 /* We'll use decode_time to interpolate timestamps
2936 * in case the input timestamps are missing */
2937 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
2939 decode_time_ts = QTSTREAMTIME_TO_GSTTIME (stream, decode_time);
2941 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
2942 " (%" GST_TIME_FORMAT ")", decode_time,
2943 GST_TIME_ARGS (decode_time_ts));
2946 if (G_UNLIKELY (!stream)) {
2947 /* we lost track of offset, we'll need to regain it,
2948 * but can delay complaining until later or avoid doing so altogether */
2952 if (G_UNLIKELY (base_offset < -1))
2954 /* Track Run node */
2956 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
2959 qtdemux_parse_trun (qtdemux, &trun_data, stream,
2960 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
2961 &running_offset, decode_time);
2962 /* iterate all siblings */
2963 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
2966 /* if no new base_offset provided for next traf,
2967 * base is end of current traf */
2968 base_offset = running_offset;
2969 running_offset = -1;
2971 /* iterate all siblings */
2972 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
2974 g_node_destroy (moof_node);
2979 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
2984 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
2989 GST_DEBUG_OBJECT (qtdemux, "lost offset");
2994 g_node_destroy (moof_node);
2995 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
2996 (_("This file is corrupt and cannot be played.")), (NULL));
3002 /* might be used if some day we actually use mfra & co
3003 * for random access to fragments,
3004 * but that will require quite some modifications and much less relying
3005 * on a sample array */
3009 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
3011 QtDemuxStream *stream;
3012 guint32 ver_flags, track_id, len, num_entries, i;
3013 guint value_size, traf_size, trun_size, sample_size;
3014 guint64 time = 0, moof_offset = 0;
3016 GstBuffer *buf = NULL;
3021 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
3023 if (!gst_byte_reader_skip (&tfra, 8))
3026 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
3029 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
3030 || !gst_byte_reader_get_uint32_be (&tfra, &len)
3031 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
3034 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
3036 stream = qtdemux_find_stream (qtdemux, track_id);
3038 goto unknown_trackid;
3040 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
3041 sample_size = (len & 3) + 1;
3042 trun_size = ((len & 12) >> 2) + 1;
3043 traf_size = ((len & 48) >> 4) + 1;
3045 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
3046 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
3048 if (num_entries == 0)
3051 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
3052 value_size + value_size + traf_size + trun_size + sample_size))
3055 g_free (stream->ra_entries);
3056 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
3057 stream->n_ra_entries = num_entries;
3059 for (i = 0; i < num_entries; i++) {
3060 qt_atom_parser_get_offset (&tfra, value_size, &time);
3061 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
3062 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
3063 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
3064 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
3066 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
3068 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
3069 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
3071 stream->ra_entries[i].ts = time;
3072 stream->ra_entries[i].moof_offset = moof_offset;
3074 /* don't want to go through the entire file and read all moofs at startup */
3076 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
3077 if (ret != GST_FLOW_OK)
3079 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
3080 moof_offset, stream);
3081 gst_buffer_unref (buf);
3085 check_update_duration (qtdemux, time);
3092 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
3097 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
3102 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
3108 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
3110 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
3111 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
3112 GstBuffer *mfro = NULL, *mfra = NULL;
3114 gboolean ret = FALSE;
3115 GNode *mfra_node, *tfra_node;
3116 guint64 mfra_offset = 0;
3117 guint32 fourcc, mfra_size;
3120 /* query upstream size in bytes */
3121 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
3122 goto size_query_failed;
3124 /* mfro box should be at the very end of the file */
3125 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
3126 if (flow != GST_FLOW_OK)
3129 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
3131 fourcc = QT_FOURCC (mfro_map.data + 4);
3132 if (fourcc != FOURCC_mfro)
3135 GST_INFO_OBJECT (qtdemux, "Found mfro box");
3136 if (mfro_map.size < 16)
3137 goto invalid_mfro_size;
3139 mfra_size = QT_UINT32 (mfro_map.data + 12);
3140 if (mfra_size >= len)
3141 goto invalid_mfra_size;
3143 mfra_offset = len - mfra_size;
3145 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
3146 mfra_offset, mfra_size);
3148 /* now get and parse mfra box */
3149 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
3150 if (flow != GST_FLOW_OK)
3153 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
3155 mfra_node = g_node_new ((guint8 *) mfra_map.data);
3156 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
3158 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
3161 qtdemux_parse_tfra (qtdemux, tfra_node);
3162 /* iterate all siblings */
3163 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
3165 g_node_destroy (mfra_node);
3167 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
3173 if (mfro_map.memory != NULL)
3174 gst_buffer_unmap (mfro, &mfro_map);
3175 gst_buffer_unref (mfro);
3178 if (mfra_map.memory != NULL)
3179 gst_buffer_unmap (mfra, &mfra_map);
3180 gst_buffer_unref (mfra);
3187 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
3192 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
3197 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
3202 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
3207 static GstFlowReturn
3208 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
3212 GstBuffer *buf = NULL;
3213 GstFlowReturn ret = GST_FLOW_OK;
3214 guint64 cur_offset = qtdemux->offset;
3217 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
3218 if (G_UNLIKELY (ret != GST_FLOW_OK))
3220 gst_buffer_map (buf, &map, GST_MAP_READ);
3221 if (G_LIKELY (map.size >= 8))
3222 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
3223 gst_buffer_unmap (buf, &map);
3224 gst_buffer_unref (buf);
3226 /* maybe we already got most we needed, so only consider this eof */
3227 if (G_UNLIKELY (length == 0)) {
3228 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
3229 (_("Invalid atom size.")),
3230 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
3231 GST_FOURCC_ARGS (fourcc)));
3238 /* record for later parsing when needed */
3239 if (!qtdemux->moof_offset) {
3240 qtdemux->moof_offset = qtdemux->offset;
3242 if (qtdemux_pull_mfro_mfra (qtdemux)) {
3245 if (qtdemux->got_moov) {
3246 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
3257 GST_LOG_OBJECT (qtdemux,
3258 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
3259 GST_FOURCC_ARGS (fourcc), cur_offset);
3260 qtdemux->offset += length;
3265 GstBuffer *moov = NULL;
3267 if (qtdemux->got_moov) {
3268 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
3269 qtdemux->offset += length;
3273 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
3274 if (ret != GST_FLOW_OK)
3276 gst_buffer_map (moov, &map, GST_MAP_READ);
3278 if (length != map.size) {
3279 /* Some files have a 'moov' atom at the end of the file which contains
3280 * a terminal 'free' atom where the body of the atom is missing.
3281 * Check for, and permit, this special case.
3283 if (map.size >= 8) {
3284 guint8 *final_data = map.data + (map.size - 8);
3285 guint32 final_length = QT_UINT32 (final_data);
3286 guint32 final_fourcc = QT_FOURCC (final_data + 4);
3288 if (final_fourcc == FOURCC_free
3289 && map.size + final_length - 8 == length) {
3290 /* Ok, we've found that special case. Allocate a new buffer with
3291 * that free atom actually present. */
3292 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
3293 gst_buffer_fill (newmoov, 0, map.data, map.size);
3294 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
3295 gst_buffer_unmap (moov, &map);
3296 gst_buffer_unref (moov);
3298 gst_buffer_map (moov, &map, GST_MAP_READ);
3303 if (length != map.size) {
3304 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
3305 (_("This file is incomplete and cannot be played.")),
3306 ("We got less than expected (received %" G_GSIZE_FORMAT
3307 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
3308 (guint) length, cur_offset));
3309 gst_buffer_unmap (moov, &map);
3310 gst_buffer_unref (moov);
3311 ret = GST_FLOW_ERROR;
3314 qtdemux->offset += length;
3316 qtdemux_parse_moov (qtdemux, map.data, length);
3317 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
3319 qtdemux_parse_tree (qtdemux);
3320 g_node_destroy (qtdemux->moov_node);
3321 gst_buffer_unmap (moov, &map);
3322 gst_buffer_unref (moov);
3323 qtdemux->moov_node = NULL;
3324 qtdemux->got_moov = TRUE;
3330 GstBuffer *ftyp = NULL;
3332 /* extract major brand; might come in handy for ISO vs QT issues */
3333 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
3334 if (ret != GST_FLOW_OK)
3336 qtdemux->offset += length;
3337 gst_buffer_map (ftyp, &map, GST_MAP_READ);
3338 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
3339 gst_buffer_unmap (ftyp, &map);
3340 gst_buffer_unref (ftyp);
3345 GstBuffer *uuid = NULL;
3347 /* uuid are extension atoms */
3348 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
3349 if (ret != GST_FLOW_OK)
3351 qtdemux->offset += length;
3352 gst_buffer_map (uuid, &map, GST_MAP_READ);
3353 qtdemux_parse_uuid (qtdemux, map.data, map.size);
3354 gst_buffer_unmap (uuid, &map);
3355 gst_buffer_unref (uuid);
3360 GstBuffer *unknown = NULL;
3362 GST_LOG_OBJECT (qtdemux,
3363 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
3364 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
3366 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
3367 if (ret != GST_FLOW_OK)
3369 gst_buffer_map (unknown, &map, GST_MAP_READ);
3370 GST_MEMDUMP ("Unknown tag", map.data, map.size);
3371 gst_buffer_unmap (unknown, &map);
3372 gst_buffer_unref (unknown);
3373 qtdemux->offset += length;
3379 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
3380 /* digested all data, show what we have */
3381 qtdemux_prepare_streams (qtdemux);
3382 ret = qtdemux_expose_streams (qtdemux);
3384 qtdemux->state = QTDEMUX_STATE_MOVIE;
3385 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
3392 /* Seeks to the previous keyframe of the indexed stream and
3393 * aligns other streams with respect to the keyframe timestamp
3394 * of indexed stream. Only called in case of Reverse Playback
3396 static GstFlowReturn
3397 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
3400 guint32 seg_idx = 0, k_index = 0;
3401 guint32 ref_seg_idx, ref_k_index;
3402 GstClockTime k_pos = 0, last_stop = 0;
3403 QtDemuxSegment *seg = NULL;
3404 QtDemuxStream *ref_str = NULL;
3405 guint64 seg_media_start_mov; /* segment media start time in mov format */
3408 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
3409 * and finally align all the other streams on that timestamp with their
3410 * respective keyframes */
3411 for (n = 0; n < qtdemux->n_streams; n++) {
3412 QtDemuxStream *str = qtdemux->streams[n];
3414 /* No candidate yet, take the first stream */
3420 /* So that stream has a segment, we prefer video streams */
3421 if (str->subtype == FOURCC_vide) {
3427 if (G_UNLIKELY (!ref_str)) {
3428 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
3432 if (G_UNLIKELY (!ref_str->from_sample)) {
3433 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
3437 /* So that stream has been playing from from_sample to to_sample. We will
3438 * get the timestamp of the previous sample and search for a keyframe before
3439 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
3440 if (ref_str->subtype == FOURCC_vide) {
3441 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
3442 ref_str->from_sample - 1);
3444 if (ref_str->from_sample >= 10)
3445 k_index = ref_str->from_sample - 10;
3451 ref_str->samples[k_index].timestamp +
3452 ref_str->samples[k_index].pts_offset;
3454 /* get current segment for that stream */
3455 seg = &ref_str->segments[ref_str->segment_index];
3456 /* Use segment start in original timescale for comparisons */
3457 seg_media_start_mov = seg->trak_media_start;
3459 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
3460 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT "\n",
3461 k_index, target_ts, seg_media_start_mov,
3462 GST_TIME_ARGS (seg->media_start));
3464 /* Crawl back through segments to find the one containing this I frame */
3465 while (target_ts < seg_media_start_mov) {
3466 GST_DEBUG_OBJECT (qtdemux,
3467 "keyframe position (sample %u) is out of segment %u " " target %"
3468 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
3469 ref_str->segment_index, target_ts, seg_media_start_mov);
3471 if (G_UNLIKELY (!ref_str->segment_index)) {
3472 /* Reached first segment, let's consider it's EOS */
3475 ref_str->segment_index--;
3476 seg = &ref_str->segments[ref_str->segment_index];
3477 /* Use segment start in original timescale for comparisons */
3478 seg_media_start_mov = seg->trak_media_start;
3480 /* Calculate time position of the keyframe and where we should stop */
3482 QTSTREAMTIME_TO_GSTTIME (ref_str,
3483 target_ts - seg->trak_media_start) + seg->time;
3485 QTSTREAMTIME_TO_GSTTIME (ref_str,
3486 ref_str->samples[ref_str->from_sample].timestamp -
3487 seg->trak_media_start) + seg->time;
3489 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
3490 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
3491 k_index, GST_TIME_ARGS (k_pos));
3493 /* Set last_stop with the keyframe timestamp we pushed of that stream */
3494 qtdemux->segment.position = last_stop;
3495 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
3496 GST_TIME_ARGS (last_stop));
3498 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
3499 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
3503 ref_seg_idx = ref_str->segment_index;
3504 ref_k_index = k_index;
3506 /* Align them all on this */
3507 for (n = 0; n < qtdemux->n_streams; n++) {
3509 GstClockTime seg_time = 0;
3510 QtDemuxStream *str = qtdemux->streams[n];
3512 /* aligning reference stream again might lead to backing up to yet another
3513 * keyframe (due to timestamp rounding issues),
3514 * potentially putting more load on downstream; so let's try to avoid */
3515 if (str == ref_str) {
3516 seg_idx = ref_seg_idx;
3517 seg = &str->segments[seg_idx];
3518 k_index = ref_k_index;
3519 GST_DEBUG_OBJECT (qtdemux, "reference stream %d segment %d, "
3520 "sample at index %d", n, ref_str->segment_index, k_index);
3522 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
3523 GST_DEBUG_OBJECT (qtdemux,
3524 "stream %d align segment %d for keyframe pos %" GST_TIME_FORMAT, n,
3525 seg_idx, GST_TIME_ARGS (k_pos));
3527 /* get segment and time in the segment */
3528 seg = &str->segments[seg_idx];
3529 seg_time = k_pos - seg->time;
3531 /* get the media time in the segment.
3532 * No adjustment for empty "filler" segments */
3533 if (seg->media_start != GST_CLOCK_TIME_NONE)
3534 seg_time += seg->media_start;
3536 /* get the index of the sample with media time */
3537 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
3538 GST_DEBUG_OBJECT (qtdemux,
3539 "stream %d sample for %" GST_TIME_FORMAT " at %u", n,
3540 GST_TIME_ARGS (seg_time), index);
3542 /* find previous keyframe */
3543 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index);
3546 /* Remember until where we want to go */
3547 str->to_sample = str->from_sample - 1;
3548 /* Define our time position */
3550 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
3551 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
3552 if (seg->media_start != GST_CLOCK_TIME_NONE)
3553 str->time_position -= seg->media_start;
3555 /* Now seek back in time */
3556 gst_qtdemux_move_stream (qtdemux, str, k_index);
3557 GST_DEBUG_OBJECT (qtdemux, "stream %d keyframe at %u, time position %"
3558 GST_TIME_FORMAT " playing from sample %u to %u", n, k_index,
3559 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
3565 return GST_FLOW_EOS;
3568 /* activate the given segment number @seg_idx of @stream at time @offset.
3569 * @offset is an absolute global position over all the segments.
3571 * This will push out a NEWSEGMENT event with the right values and
3572 * position the stream index to the first decodable sample before
3578 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
3579 guint32 seg_idx, GstClockTime offset)
3582 QtDemuxSegment *segment;
3583 guint32 index, kf_index;
3584 GstClockTime seg_time;
3585 GstClockTime start, stop, time;
3588 GST_LOG_OBJECT (qtdemux, "activate segment %d, offset %" GST_TIME_FORMAT,
3589 seg_idx, GST_TIME_ARGS (offset));
3591 /* update the current segment */
3592 stream->segment_index = seg_idx;
3594 /* get the segment */
3595 segment = &stream->segments[seg_idx];
3597 if (G_UNLIKELY (offset < segment->time)) {
3598 GST_WARNING_OBJECT (qtdemux, "offset < segment->time %" GST_TIME_FORMAT,
3599 GST_TIME_ARGS (segment->time));
3603 /* segment lies beyond total indicated duration */
3604 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
3605 segment->time > qtdemux->segment.duration)) {
3606 GST_WARNING_OBJECT (qtdemux, "file duration %" GST_TIME_FORMAT
3607 " < segment->time %" GST_TIME_FORMAT,
3608 GST_TIME_ARGS (qtdemux->segment.duration),
3609 GST_TIME_ARGS (segment->time));
3613 /* get time in this segment */
3614 seg_time = offset - segment->time;
3616 GST_LOG_OBJECT (qtdemux, "seg_time %" GST_TIME_FORMAT,
3617 GST_TIME_ARGS (seg_time));
3619 if (G_UNLIKELY (seg_time > segment->duration)) {
3620 GST_LOG_OBJECT (qtdemux, "seg_time > segment->duration %" GST_TIME_FORMAT,
3621 GST_TIME_ARGS (segment->duration));
3622 seg_time = segment->duration;
3625 /* qtdemux->segment.stop is in outside-time-realm, whereas
3626 * segment->media_stop is in track-time-realm.
3628 * In order to compare the two, we need to bring segment.stop
3629 * into the track-time-realm */
3631 stop = qtdemux->segment.stop;
3632 if (stop == GST_CLOCK_TIME_NONE)
3633 stop = qtdemux->segment.duration;
3634 if (stop == GST_CLOCK_TIME_NONE)
3635 stop = segment->media_stop;
3638 MIN (segment->media_stop, stop - segment->time + segment->media_start);
3640 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
3641 start = segment->time + seg_time;
3643 } else if (qtdemux->segment.rate >= 0) {
3644 start = MIN (segment->media_start + seg_time, stop);
3647 if (segment->media_start >= qtdemux->segment.start) {
3648 time = segment->time;
3650 time = segment->time + (qtdemux->segment.start - segment->media_start);
3653 start = MAX (segment->media_start, qtdemux->segment.start);
3654 stop = MIN (segment->media_start + seg_time, stop);
3657 GST_DEBUG_OBJECT (qtdemux, "newsegment %d from %" GST_TIME_FORMAT
3658 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
3659 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
3661 /* combine global rate with that of the segment */
3662 rate = segment->rate * qtdemux->segment.rate;
3664 /* Copy flags from main segment */
3665 stream->segment.flags = qtdemux->segment.flags;
3667 /* update the segment values used for clipping */
3668 /* accumulate previous segments */
3669 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
3670 stream->segment.base += (stream->segment.stop - stream->segment.start) /
3671 ABS (stream->segment.rate);
3672 stream->segment.rate = rate;
3673 stream->segment.start = start;
3674 stream->segment.stop = stop;
3675 stream->segment.time = time;
3676 stream->segment.position = start;
3677 stream->segment.base =
3679 qtdemux->segment_base ? segment->time - qtdemux->segment_base : 0;
3681 /* now prepare and send the segment */
3683 event = gst_event_new_segment (&stream->segment);
3684 if (stream->segment_seqnum) {
3685 gst_event_set_seqnum (event, stream->segment_seqnum);
3686 stream->segment_seqnum = 0;
3688 gst_pad_push_event (stream->pad, event);
3689 /* clear to send tags on this pad now */
3690 gst_qtdemux_push_tags (qtdemux, stream);
3693 /* in the fragmented case, we pick a fragment that starts before our
3694 * desired position and rely on downstream to wait for a keyframe
3695 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
3696 * tfra entries tells us which trun/sample the key unit is in, but we don't
3697 * make use of this additional information at the moment) */
3698 if (qtdemux->fragmented) {
3699 stream->to_sample = G_MAXUINT32;
3703 /* and move to the keyframe before the indicated media time of the
3705 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
3706 if (qtdemux->segment.rate >= 0) {
3707 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
3708 stream->to_sample = G_MAXUINT32;
3709 GST_DEBUG_OBJECT (qtdemux,
3710 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
3711 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
3712 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
3714 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
3715 stream->to_sample = index;
3716 GST_DEBUG_OBJECT (qtdemux,
3717 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
3718 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
3719 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
3722 GST_DEBUG_OBJECT (qtdemux, "No need to look for keyframe, "
3723 "this is an empty segment");
3727 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
3728 * encountered an error and printed a message so we return appropriately */
3732 /* we're at the right spot */
3733 if (index == stream->sample_index) {
3734 GST_DEBUG_OBJECT (qtdemux, "we are at the right index");
3738 /* find keyframe of the target index */
3739 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index);
3742 /* indent does stupid stuff with stream->samples[].timestamp */
3744 /* if we move forwards, we don't have to go back to the previous
3745 * keyframe since we already sent that. We can also just jump to
3746 * the keyframe right before the target index if there is one. */
3747 if (index > stream->sample_index) {
3748 /* moving forwards check if we move past a keyframe */
3749 if (kf_index > stream->sample_index) {
3750 GST_DEBUG_OBJECT (qtdemux,
3751 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
3752 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
3753 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
3754 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
3756 GST_DEBUG_OBJECT (qtdemux,
3757 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
3758 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
3759 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
3762 GST_DEBUG_OBJECT (qtdemux,
3763 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
3764 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
3765 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
3766 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
3774 /* prepare to get the current sample of @stream, getting essential values.
3776 * This function will also prepare and send the segment when needed.
3778 * Return FALSE if the stream is EOS.
3783 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
3784 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
3785 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
3786 gboolean * keyframe)
3788 QtDemuxSample *sample;
3789 GstClockTime time_position;
3792 g_return_val_if_fail (stream != NULL, FALSE);
3794 time_position = stream->time_position;
3795 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
3798 seg_idx = stream->segment_index;
3799 if (G_UNLIKELY (seg_idx == -1)) {
3800 /* find segment corresponding to time_position if we are looking
3802 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
3805 /* different segment, activate it, sample_index will be set. */
3806 if (G_UNLIKELY (stream->segment_index != seg_idx))
3807 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
3809 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->segments[stream->
3811 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
3813 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
3814 " prepare empty sample");
3817 *pts = *dts = time_position;
3818 *duration = seg->duration - (time_position - seg->time);
3825 if (stream->sample_index == -1)
3826 stream->sample_index = 0;
3828 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
3829 stream->sample_index, stream->n_samples);
3831 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
3832 if (!qtdemux->fragmented)
3835 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
3839 GST_OBJECT_LOCK (qtdemux);
3840 flow = qtdemux_add_fragmented_samples (qtdemux);
3841 GST_OBJECT_UNLOCK (qtdemux);
3843 if (flow != GST_FLOW_OK)
3846 while (stream->sample_index >= stream->n_samples);
3849 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
3850 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
3851 stream->sample_index);
3855 /* now get the info for the sample we're at */
3856 sample = &stream->samples[stream->sample_index];
3858 *dts = QTSAMPLE_DTS (stream, sample);
3859 *pts = QTSAMPLE_PTS (stream, sample);
3860 *offset = sample->offset;
3861 *size = sample->size;
3862 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
3863 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
3870 stream->time_position = GST_CLOCK_TIME_NONE;
3875 /* move to the next sample in @stream.
3877 * Moves to the next segment when needed.
3880 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
3882 QtDemuxSample *sample;
3883 QtDemuxSegment *segment;
3885 /* get current segment */
3886 segment = &stream->segments[stream->segment_index];
3888 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
3889 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
3893 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
3894 /* Mark the stream as EOS */
3895 GST_DEBUG_OBJECT (qtdemux,
3896 "reached max allowed sample %u, mark EOS", stream->to_sample);
3897 stream->time_position = GST_CLOCK_TIME_NONE;
3901 /* move to next sample */
3902 stream->sample_index++;
3903 stream->offset_in_sample = 0;
3905 /* reached the last sample, we need the next segment */
3906 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
3909 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
3910 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
3911 stream->sample_index);
3915 /* get next sample */
3916 sample = &stream->samples[stream->sample_index];
3918 /* see if we are past the segment */
3919 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
3922 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
3923 /* inside the segment, update time_position, looks very familiar to
3924 * GStreamer segments, doesn't it? */
3925 stream->time_position =
3926 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
3928 /* not yet in segment, time does not yet increment. This means
3929 * that we are still prerolling keyframes to the decoder so it can
3930 * decode the first sample of the segment. */
3931 stream->time_position = segment->time;
3935 /* move to the next segment */
3938 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
3940 if (stream->segment_index == stream->n_segments - 1) {
3941 /* are we at the end of the last segment, we're EOS */
3942 stream->time_position = GST_CLOCK_TIME_NONE;
3944 /* else we're only at the end of the current segment */
3945 stream->time_position = segment->stop_time;
3947 /* make sure we select a new segment */
3948 stream->segment_index = -1;
3953 gst_qtdemux_sync_streams (GstQTDemux * demux)
3957 if (demux->n_streams <= 1)
3960 for (i = 0; i < demux->n_streams; i++) {
3961 QtDemuxStream *stream;
3962 GstClockTime end_time;
3964 stream = demux->streams[i];
3969 /* TODO advance time on subtitle streams here, if any some day */
3971 /* some clips/trailers may have unbalanced streams at the end,
3972 * so send EOS on shorter stream to prevent stalling others */
3974 /* do not mess with EOS if SEGMENT seeking */
3975 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
3978 if (demux->pullbased) {
3979 /* loop mode is sample time based */
3980 if (!STREAM_IS_EOS (stream))
3983 /* push mode is byte position based */
3984 if (stream->n_samples &&
3985 stream->samples[stream->n_samples - 1].offset >= demux->offset)
3989 if (stream->sent_eos)
3992 /* only act if some gap */
3993 end_time = stream->segments[stream->n_segments - 1].stop_time;
3994 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
3995 ", stream end: %" GST_TIME_FORMAT,
3996 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
3997 if (GST_CLOCK_TIME_IS_VALID (end_time)
3998 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
3999 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
4000 GST_PAD_NAME (stream->pad));
4001 stream->sent_eos = TRUE;
4002 gst_pad_push_event (stream->pad, gst_event_new_eos ());
4007 /* EOS and NOT_LINKED need to be combined. This means that we return:
4009 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
4010 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
4012 static GstFlowReturn
4013 gst_qtdemux_combine_flows (GstQTDemux * demux, GstFlowReturn ret)
4015 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
4017 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
4019 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
4023 /* the input buffer metadata must be writable. Returns NULL when the buffer is
4024 * completely clipped
4026 * Should be used only with raw buffers */
4028 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
4031 guint64 start, stop, cstart, cstop, diff;
4032 GstClockTime pts, duration;
4034 gint num_rate, denom_rate;
4039 osize = size = gst_buffer_get_size (buf);
4042 /* depending on the type, setup the clip parameters */
4043 if (stream->subtype == FOURCC_soun) {
4044 frame_size = stream->bytes_per_frame;
4045 num_rate = GST_SECOND;
4046 denom_rate = (gint) stream->rate;
4048 } else if (stream->subtype == FOURCC_vide) {
4050 num_rate = stream->fps_n;
4051 denom_rate = stream->fps_d;
4056 if (frame_size <= 0)
4057 goto bad_frame_size;
4059 /* we can only clip if we have a valid pts */
4060 pts = GST_BUFFER_PTS (buf);
4061 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
4064 duration = GST_BUFFER_DURATION (buf);
4066 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
4068 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
4072 stop = start + duration;
4074 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
4075 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
4078 /* see if some clipping happened */
4079 diff = cstart - start;
4085 /* bring clipped time to samples and to bytes */
4086 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
4089 GST_DEBUG_OBJECT (qtdemux,
4090 "clipping start to %" GST_TIME_FORMAT " %"
4091 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
4097 diff = stop - cstop;
4102 /* bring clipped time to samples and then to bytes */
4103 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
4105 GST_DEBUG_OBJECT (qtdemux,
4106 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
4107 " bytes", GST_TIME_ARGS (cstop), diff);
4112 if (offset != 0 || size != osize)
4113 gst_buffer_resize (buf, offset, size);
4115 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
4116 GST_BUFFER_PTS (buf) = pts;
4117 GST_BUFFER_DURATION (buf) = duration;
4121 /* dropped buffer */
4124 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
4129 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
4134 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
4139 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
4140 gst_buffer_unref (buf);
4145 /* the input buffer metadata must be writable,
4146 * but time/duration etc not yet set and need not be preserved */
4148 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
4155 /* not many cases for now */
4156 if (G_UNLIKELY (stream->fourcc == FOURCC_mp4s)) {
4157 /* send a one time dvd clut event */
4158 if (stream->pending_event && stream->pad)
4159 gst_pad_push_event (stream->pad, stream->pending_event);
4160 stream->pending_event = NULL;
4163 if (G_UNLIKELY (stream->subtype != FOURCC_text
4164 && stream->subtype != FOURCC_sbtl &&
4165 stream->subtype != FOURCC_subp)) {
4169 gst_buffer_map (buf, &map, GST_MAP_READ);
4171 /* empty buffer is sent to terminate previous subtitle */
4172 if (map.size <= 2) {
4173 gst_buffer_unmap (buf, &map);
4174 gst_buffer_unref (buf);
4177 if (stream->subtype == FOURCC_subp) {
4178 /* That's all the processing needed for subpictures */
4179 gst_buffer_unmap (buf, &map);
4183 nsize = GST_READ_UINT16_BE (map.data);
4184 nsize = MIN (nsize, map.size - 2);
4186 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
4189 /* takes care of UTF-8 validation or UTF-16 recognition,
4190 * no other encoding expected */
4191 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
4192 gst_buffer_unmap (buf, &map);
4194 gst_buffer_unref (buf);
4195 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
4197 /* this should not really happen unless the subtitle is corrupted */
4198 gst_buffer_unref (buf);
4202 /* FIXME ? convert optional subsequent style info to markup */
4207 /* Sets a buffer's attributes properly and pushes it downstream.
4208 * Also checks for additional actions and custom processing that may
4209 * need to be done first.
4211 static GstFlowReturn
4212 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
4213 QtDemuxStream * stream, GstBuffer * buf,
4214 GstClockTime dts, GstClockTime pts, GstClockTime duration,
4215 gboolean keyframe, GstClockTime position, guint64 byte_position)
4217 GstFlowReturn ret = GST_FLOW_OK;
4219 /* offset the timestamps according to the edit list */
4221 if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) {
4225 gst_buffer_map (buf, &map, GST_MAP_READ);
4226 url = g_strndup ((gchar *) map.data, map.size);
4227 gst_buffer_unmap (buf, &map);
4228 if (url != NULL && strlen (url) != 0) {
4229 /* we have RTSP redirect now */
4230 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
4231 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
4232 gst_structure_new ("redirect",
4233 "new-location", G_TYPE_STRING, url, NULL)));
4234 qtdemux->posted_redirect = TRUE;
4236 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
4242 /* position reporting */
4243 if (qtdemux->segment.rate >= 0) {
4244 qtdemux->segment.position = position;
4245 gst_qtdemux_sync_streams (qtdemux);
4248 if (G_UNLIKELY (!stream->pad)) {
4249 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
4250 gst_buffer_unref (buf);
4254 /* send out pending buffers */
4255 while (stream->buffers) {
4256 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
4258 if (G_UNLIKELY (stream->discont)) {
4259 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
4260 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
4261 stream->discont = FALSE;
4263 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
4266 gst_pad_push (stream->pad, buffer);
4268 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
4271 /* we're going to modify the metadata */
4272 buf = gst_buffer_make_writable (buf);
4274 if (G_UNLIKELY (stream->need_process))
4275 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
4281 GST_BUFFER_DTS (buf) = dts;
4282 GST_BUFFER_PTS (buf) = pts;
4283 GST_BUFFER_DURATION (buf) = duration;
4284 GST_BUFFER_OFFSET (buf) = -1;
4285 GST_BUFFER_OFFSET_END (buf) = -1;
4287 if (G_UNLIKELY (stream->rgb8_palette))
4288 gst_buffer_append_memory (buf, gst_memory_ref (stream->rgb8_palette));
4290 if (G_UNLIKELY (stream->padding)) {
4291 gst_buffer_resize (buf, stream->padding, -1);
4294 if (G_UNLIKELY (qtdemux->element_index)) {
4295 GstClockTime stream_time;
4298 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
4300 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
4301 GST_LOG_OBJECT (qtdemux,
4302 "adding association %" GST_TIME_FORMAT "-> %"
4303 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
4304 gst_index_add_association (qtdemux->element_index,
4306 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
4307 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
4308 GST_FORMAT_BYTES, byte_position, NULL);
4313 if (stream->need_clip)
4314 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
4316 if (G_UNLIKELY (buf == NULL))
4319 if (G_UNLIKELY (stream->discont)) {
4320 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
4321 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
4322 stream->discont = FALSE;
4324 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
4328 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
4329 stream->on_keyframe = FALSE;
4331 stream->on_keyframe = TRUE;
4335 GST_LOG_OBJECT (qtdemux,
4336 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
4337 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
4338 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
4339 GST_PAD_NAME (stream->pad));
4341 ret = gst_pad_push (stream->pad, buf);
4343 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
4344 /* mark position in stream, we'll need this to know when to send GAP event */
4345 stream->segment.position = pts + duration;
4352 static const QtDemuxRandomAccessEntry *
4353 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4354 GstClockTime pos, gboolean after)
4356 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
4357 guint n_entries = stream->n_ra_entries;
4360 /* we assume the table is sorted */
4361 for (i = 0; i < n_entries; ++i) {
4362 if (entries[i].ts > pos)
4366 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
4367 * probably okay to assume that the index lists the very first fragment */
4374 return &entries[i - 1];
4378 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
4380 const QtDemuxRandomAccessEntry *best_entry = NULL;
4383 GST_OBJECT_LOCK (qtdemux);
4385 g_assert (qtdemux->n_streams > 0);
4387 for (i = 0; i < qtdemux->n_streams; i++) {
4388 const QtDemuxRandomAccessEntry *entry;
4389 QtDemuxStream *stream;
4390 gboolean is_audio_or_video;
4392 stream = qtdemux->streams[i];
4394 g_free (stream->samples);
4395 stream->samples = NULL;
4396 stream->n_samples = 0;
4397 stream->stbl_index = -1; /* no samples have yet been parsed */
4398 stream->sample_index = -1;
4400 if (stream->ra_entries == NULL)
4403 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
4404 is_audio_or_video = TRUE;
4406 is_audio_or_video = FALSE;
4409 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
4410 stream->time_position, !is_audio_or_video);
4412 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
4413 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
4415 stream->pending_seek = entry;
4417 /* decide position to jump to just based on audio/video tracks, not subs */
4418 if (!is_audio_or_video)
4421 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
4425 if (best_entry == NULL)
4428 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
4429 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
4430 GST_TIME_ARGS (qtdemux->streams[0]->time_position),
4431 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
4433 qtdemux->moof_offset = best_entry->moof_offset;
4435 qtdemux_add_fragmented_samples (qtdemux);
4437 GST_OBJECT_UNLOCK (qtdemux);
4441 static GstFlowReturn
4442 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
4444 GstFlowReturn ret = GST_FLOW_OK;
4445 GstBuffer *buf = NULL;
4446 QtDemuxStream *stream;
4447 GstClockTime min_time;
4449 GstClockTime dts = GST_CLOCK_TIME_NONE;
4450 GstClockTime pts = GST_CLOCK_TIME_NONE;
4451 GstClockTime duration = 0;
4452 gboolean keyframe = FALSE;
4453 guint sample_size = 0;
4459 gst_qtdemux_push_pending_newsegment (qtdemux);
4461 if (qtdemux->fragmented_seek_pending) {
4462 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
4463 gst_qtdemux_do_fragmented_seek (qtdemux);
4464 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
4465 qtdemux->fragmented_seek_pending = FALSE;
4468 /* Figure out the next stream sample to output, min_time is expressed in
4469 * global time and runs over the edit list segments. */
4470 min_time = G_MAXUINT64;
4472 for (i = 0; i < qtdemux->n_streams; i++) {
4473 GstClockTime position;
4475 stream = qtdemux->streams[i];
4476 position = stream->time_position;
4478 /* position of -1 is EOS */
4479 if (position != GST_CLOCK_TIME_NONE && position < min_time) {
4480 min_time = position;
4485 if (G_UNLIKELY (index == -1)) {
4486 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
4490 /* check for segment end */
4491 if (G_UNLIKELY (qtdemux->segment.stop != -1
4492 && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
4493 || (qtdemux->segment.rate < 0
4494 && qtdemux->segment.start > min_time))
4495 && qtdemux->streams[index]->on_keyframe)) {
4496 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
4497 qtdemux->streams[index]->time_position = GST_CLOCK_TIME_NONE;
4501 /* gap events for subtitle streams */
4502 for (i = 0; i < qtdemux->n_streams; i++) {
4503 stream = qtdemux->streams[i];
4504 if (stream->pad && (stream->subtype == FOURCC_subp
4505 || stream->subtype == FOURCC_text
4506 || stream->subtype == FOURCC_sbtl)) {
4507 /* send one second gap events until the stream catches up */
4508 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
4509 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
4510 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
4511 stream->segment.position + GST_SECOND < min_time) {
4513 gst_event_new_gap (stream->segment.position, GST_SECOND);
4514 gst_pad_push_event (stream->pad, gap);
4515 stream->segment.position += GST_SECOND;
4520 stream = qtdemux->streams[index];
4521 if (stream->new_caps) {
4522 gst_qtdemux_configure_stream (qtdemux, stream);
4523 qtdemux_do_allocation (qtdemux, stream);
4526 /* fetch info for the current sample of this stream */
4527 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
4528 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
4531 GST_DEBUG_OBJECT (qtdemux,
4532 "pushing from stream %d, empty %d offset %" G_GUINT64_FORMAT
4533 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
4534 ", duration %" GST_TIME_FORMAT, index, empty, offset, sample_size,
4535 GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
4537 if (G_UNLIKELY (empty)) {
4538 /* empty segment, push a gap and move to the next one */
4539 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
4540 stream->segment.position = pts + duration;
4544 /* hmm, empty sample, skip and move to next sample */
4545 if (G_UNLIKELY (sample_size <= 0))
4548 /* last pushed sample was out of boundary, goto next sample */
4549 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
4552 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
4555 GST_DEBUG_OBJECT (qtdemux,
4556 "size %d larger than stream max_buffer_size %d, trimming",
4557 sample_size, stream->max_buffer_size);
4559 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
4562 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
4565 if (stream->use_allocator) {
4566 /* if we have a per-stream allocator, use it */
4567 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
4570 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
4572 if (G_UNLIKELY (ret != GST_FLOW_OK))
4575 if (size != sample_size) {
4576 pts += gst_util_uint64_scale_int (GST_SECOND,
4577 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
4578 dts += gst_util_uint64_scale_int (GST_SECOND,
4579 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
4580 duration = gst_util_uint64_scale_int (GST_SECOND,
4581 size / stream->bytes_per_frame, stream->timescale);
4584 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
4585 dts, pts, duration, keyframe, min_time, offset);
4587 if (size != sample_size) {
4588 QtDemuxSample *sample = &stream->samples[stream->sample_index];
4589 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
4591 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
4592 sample->timestamp + stream->offset_in_sample / stream->bytes_per_frame);
4593 if (time_position >= segment->media_start) {
4594 /* inside the segment, update time_position, looks very familiar to
4595 * GStreamer segments, doesn't it? */
4596 stream->time_position = (time_position - segment->media_start) +
4599 /* not yet in segment, time does not yet increment. This means
4600 * that we are still prerolling keyframes to the decoder so it can
4601 * decode the first sample of the segment. */
4602 stream->time_position = segment->time;
4607 ret = gst_qtdemux_combine_flows (qtdemux, ret);
4608 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
4609 * we have no more data for the pad to push */
4610 if (ret == GST_FLOW_EOS)
4613 stream->offset_in_sample += size;
4614 if (stream->offset_in_sample >= sample_size) {
4615 gst_qtdemux_advance_sample (qtdemux, stream);
4620 gst_qtdemux_advance_sample (qtdemux, stream);
4628 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
4634 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
4635 /* EOS will be raised if all are EOS */
4642 gst_qtdemux_loop (GstPad * pad)
4644 GstQTDemux *qtdemux;
4648 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
4650 cur_offset = qtdemux->offset;
4651 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %d",
4652 cur_offset, qtdemux->state);
4654 switch (qtdemux->state) {
4655 case QTDEMUX_STATE_INITIAL:
4656 case QTDEMUX_STATE_HEADER:
4657 ret = gst_qtdemux_loop_state_header (qtdemux);
4659 case QTDEMUX_STATE_MOVIE:
4660 ret = gst_qtdemux_loop_state_movie (qtdemux);
4661 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
4662 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
4670 /* if something went wrong, pause */
4671 if (ret != GST_FLOW_OK)
4675 gst_object_unref (qtdemux);
4681 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
4682 (NULL), ("streaming stopped, invalid state"));
4683 gst_pad_pause_task (pad);
4684 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
4689 const gchar *reason = gst_flow_get_name (ret);
4691 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
4693 gst_pad_pause_task (pad);
4695 /* fatal errors need special actions */
4697 if (ret == GST_FLOW_EOS) {
4698 if (qtdemux->n_streams == 0) {
4699 /* we have no streams, post an error */
4700 gst_qtdemux_post_no_playable_stream_error (qtdemux);
4702 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
4705 if ((stop = qtdemux->segment.stop) == -1)
4706 stop = qtdemux->segment.duration;
4708 if (qtdemux->segment.rate >= 0) {
4709 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
4710 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
4711 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
4712 GST_FORMAT_TIME, stop));
4713 gst_qtdemux_push_event (qtdemux,
4714 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
4716 /* For Reverse Playback */
4717 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
4718 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
4719 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
4720 GST_FORMAT_TIME, qtdemux->segment.start));
4721 gst_qtdemux_push_event (qtdemux,
4722 gst_event_new_segment_done (GST_FORMAT_TIME,
4723 qtdemux->segment.start));
4726 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
4727 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
4729 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
4730 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
4731 (NULL), ("streaming stopped, reason %s", reason));
4732 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
4741 * Returns if there are samples to be played.
4744 has_next_entry (GstQTDemux * demux)
4746 QtDemuxStream *stream;
4749 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
4751 for (i = 0; i < demux->n_streams; i++) {
4752 stream = demux->streams[i];
4754 if (stream->sample_index == -1) {
4755 stream->sample_index = 0;
4756 stream->offset_in_sample = 0;
4759 if (stream->sample_index >= stream->n_samples) {
4760 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
4763 GST_DEBUG_OBJECT (demux, "Found a sample");
4767 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
4774 * Returns the size of the first entry at the current offset.
4775 * If -1, there are none (which means EOS or empty file).
4778 next_entry_size (GstQTDemux * demux)
4780 QtDemuxStream *stream;
4783 guint64 smalloffs = (guint64) - 1;
4784 QtDemuxSample *sample;
4786 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
4789 for (i = 0; i < demux->n_streams; i++) {
4790 stream = demux->streams[i];
4792 if (stream->sample_index == -1) {
4793 stream->sample_index = 0;
4794 stream->offset_in_sample = 0;
4797 if (stream->sample_index >= stream->n_samples) {
4798 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
4802 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
4803 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
4804 stream->sample_index);
4808 sample = &stream->samples[stream->sample_index];
4810 GST_LOG_OBJECT (demux,
4811 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
4812 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
4813 sample->offset, sample->size);
4815 if (((smalloffs == -1)
4816 || (sample->offset < smalloffs)) && (sample->size)) {
4818 smalloffs = sample->offset;
4822 GST_LOG_OBJECT (demux,
4823 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
4824 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
4829 stream = demux->streams[smallidx];
4830 sample = &stream->samples[stream->sample_index];
4832 if (sample->offset >= demux->offset) {
4833 demux->todrop = sample->offset - demux->offset;
4834 return sample->size + demux->todrop;
4837 GST_DEBUG_OBJECT (demux,
4838 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
4843 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
4845 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
4847 gst_element_post_message (GST_ELEMENT_CAST (demux),
4848 gst_message_new_element (GST_OBJECT_CAST (demux),
4849 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
4853 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
4858 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
4861 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
4862 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
4863 GST_SEEK_TYPE_NONE, -1);
4865 res = gst_pad_push_event (demux->sinkpad, event);
4870 /* check for seekable upstream, above and beyond a mere query */
4872 gst_qtdemux_check_seekability (GstQTDemux * demux)
4875 gboolean seekable = FALSE;
4876 gint64 start = -1, stop = -1;
4878 if (demux->upstream_size)
4881 query = gst_query_new_seeking (GST_FORMAT_BYTES);
4882 if (!gst_pad_peer_query (demux->sinkpad, query)) {
4883 GST_DEBUG_OBJECT (demux, "seeking query failed");
4887 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
4889 /* try harder to query upstream size if we didn't get it the first time */
4890 if (seekable && stop == -1) {
4891 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
4892 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
4895 /* if upstream doesn't know the size, it's likely that it's not seekable in
4896 * practice even if it technically may be seekable */
4897 if (seekable && (start != 0 || stop <= start)) {
4898 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
4903 gst_query_unref (query);
4905 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
4906 G_GUINT64_FORMAT ")", seekable, start, stop);
4907 demux->upstream_seekable = seekable;
4908 demux->upstream_size = seekable ? stop : -1;
4911 /* FIXME, unverified after edit list updates */
4912 static GstFlowReturn
4913 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
4917 demux = GST_QTDEMUX (parent);
4919 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
4922 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
4924 for (i = 0; i < demux->n_streams; i++) {
4925 demux->streams[i]->discont = TRUE;
4929 gst_adapter_push (demux->adapter, inbuf);
4931 GST_DEBUG_OBJECT (demux,
4932 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
4933 demux->neededbytes, gst_adapter_available (demux->adapter));
4935 return gst_qtdemux_process_adapter (demux, FALSE);
4938 static GstFlowReturn
4939 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
4941 GstFlowReturn ret = GST_FLOW_OK;
4943 /* we never really mean to buffer that much */
4944 if (demux->neededbytes == -1) {
4948 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
4949 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
4951 GST_DEBUG_OBJECT (demux,
4952 "state:%d , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT,
4953 demux->state, demux->neededbytes, demux->offset);
4955 switch (demux->state) {
4956 case QTDEMUX_STATE_INITIAL:{
4961 gst_qtdemux_check_seekability (demux);
4963 data = gst_adapter_map (demux->adapter, demux->neededbytes);
4965 /* get fourcc/length, set neededbytes */
4966 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
4968 gst_adapter_unmap (demux->adapter);
4970 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
4971 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
4973 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4974 (_("This file is invalid and cannot be played.")),
4975 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
4976 GST_FOURCC_ARGS (fourcc)));
4977 ret = GST_FLOW_ERROR;
4980 if (fourcc == FOURCC_mdat) {
4981 gint next_entry = next_entry_size (demux);
4982 if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
4983 /* we have the headers, start playback */
4984 demux->state = QTDEMUX_STATE_MOVIE;
4985 demux->neededbytes = next_entry;
4986 demux->mdatleft = size;
4988 /* no headers yet, try to get them */
4991 guint64 old, target;
4994 old = demux->offset;
4995 target = old + size;
4997 /* try to jump over the atom with a seek */
4998 /* only bother if it seems worth doing so,
4999 * and avoids possible upstream/server problems */
5000 if (demux->upstream_seekable &&
5001 demux->upstream_size > 4 * (1 << 20)) {
5002 res = qtdemux_seek_offset (demux, target);
5004 GST_DEBUG_OBJECT (demux, "skipping seek");
5009 GST_DEBUG_OBJECT (demux, "seek success");
5010 /* remember the offset fo the first mdat so we can seek back to it
5011 * after we have the headers */
5012 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
5013 demux->first_mdat = old;
5014 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
5017 /* seek worked, continue reading */
5018 demux->offset = target;
5019 demux->neededbytes = 16;
5020 demux->state = QTDEMUX_STATE_INITIAL;
5022 /* seek failed, need to buffer */
5023 demux->offset = old;
5024 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
5025 /* there may be multiple mdat (or alike) buffers */
5027 if (demux->mdatbuffer)
5028 bs = gst_buffer_get_size (demux->mdatbuffer);
5031 if (size + bs > 10 * (1 << 20))
5033 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
5034 demux->neededbytes = size;
5035 if (!demux->mdatbuffer)
5036 demux->mdatoffset = demux->offset;
5039 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
5040 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
5041 (_("This file is invalid and cannot be played.")),
5042 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
5043 GST_FOURCC_ARGS (fourcc), size));
5044 ret = GST_FLOW_ERROR;
5047 /* this means we already started buffering and still no moov header,
5048 * let's continue buffering everything till we get moov */
5049 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
5050 || fourcc == FOURCC_moof))
5052 demux->neededbytes = size;
5053 demux->state = QTDEMUX_STATE_HEADER;
5057 case QTDEMUX_STATE_HEADER:{
5061 GST_DEBUG_OBJECT (demux, "In header");
5063 data = gst_adapter_map (demux->adapter, demux->neededbytes);
5065 /* parse the header */
5066 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
5068 if (fourcc == FOURCC_moov) {
5069 /* in usual fragmented setup we could try to scan for more
5070 * and end up at the the moov (after mdat) again */
5071 if (demux->got_moov && demux->n_streams > 0 &&
5073 || demux->last_moov_offset == demux->offset)) {
5074 GST_DEBUG_OBJECT (demux,
5075 "Skipping moov atom as we have (this) one already");
5077 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
5079 if (demux->got_moov && demux->fragmented) {
5080 GST_DEBUG_OBJECT (demux,
5081 "Got a second moov, clean up data from old one");
5082 if (demux->moov_node)
5083 g_node_destroy (demux->moov_node);
5084 demux->moov_node = NULL;
5085 demux->moov_node_compressed = NULL;
5087 /* prepare newsegment to send when streaming actually starts */
5088 if (!demux->pending_newsegment)
5089 demux->pending_newsegment =
5090 gst_event_new_segment (&demux->segment);
5093 demux->last_moov_offset = demux->offset;
5095 qtdemux_parse_moov (demux, data, demux->neededbytes);
5096 qtdemux_node_dump (demux, demux->moov_node);
5097 qtdemux_parse_tree (demux);
5098 qtdemux_prepare_streams (demux);
5099 if (!demux->got_moov)
5100 qtdemux_expose_streams (demux);
5104 for (n = 0; n < demux->n_streams; n++) {
5105 QtDemuxStream *stream = demux->streams[n];
5107 gst_qtdemux_configure_stream (demux, stream);
5111 demux->got_moov = TRUE;
5113 g_node_destroy (demux->moov_node);
5114 demux->moov_node = NULL;
5115 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
5117 } else if (fourcc == FOURCC_moof) {
5118 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
5120 GstClockTime prev_pts;
5121 guint64 prev_offset;
5123 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
5126 * The timestamp of the moof buffer is relevant as some scenarios
5127 * won't have the initial timestamp in the atoms. Whenever a new
5128 * buffer has started, we get that buffer's PTS and use it as a base
5129 * timestamp for the trun entries.
5131 * To keep track of the current buffer timestamp and starting point
5132 * we use gst_adapter_prev_pts that gives us the PTS and the distance
5133 * from the beggining of the buffer, with the distance and demux->offset
5134 * we know if it is still the same buffer or not.
5136 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
5137 prev_offset = demux->offset - dist;
5138 if (demux->fragment_start_offset == -1
5139 || prev_offset > demux->fragment_start_offset) {
5140 demux->fragment_start_offset = prev_offset;
5141 demux->fragment_start = prev_pts;
5142 GST_DEBUG_OBJECT (demux,
5143 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
5144 GST_TIME_FORMAT, demux->fragment_start_offset,
5145 GST_TIME_ARGS (demux->fragment_start));
5148 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
5149 demux->offset, NULL)) {
5150 gst_adapter_unmap (demux->adapter);
5151 ret = GST_FLOW_ERROR;
5154 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
5155 if (demux->mss_mode && !demux->exposed) {
5156 if (!demux->pending_newsegment) {
5158 gst_segment_init (&segment, GST_FORMAT_TIME);
5159 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
5160 demux->pending_newsegment = gst_event_new_segment (&segment);
5162 qtdemux_expose_streams (demux);
5165 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
5167 } else if (fourcc == FOURCC_ftyp) {
5168 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
5169 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
5170 } else if (fourcc == FOURCC_uuid) {
5171 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
5172 qtdemux_parse_uuid (demux, data, demux->neededbytes);
5174 GST_WARNING_OBJECT (demux,
5175 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
5176 GST_FOURCC_ARGS (fourcc));
5177 /* Let's jump that one and go back to initial state */
5179 gst_adapter_unmap (demux->adapter);
5182 if (demux->mdatbuffer && demux->n_streams) {
5183 gsize remaining_data_size = 0;
5185 /* the mdat was before the header */
5186 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
5187 demux->n_streams, demux->mdatbuffer);
5188 /* restore our adapter/offset view of things with upstream;
5189 * put preceding buffered data ahead of current moov data.
5190 * This should also handle evil mdat, moov, mdat cases and alike */
5191 gst_adapter_flush (demux->adapter, demux->neededbytes);
5193 /* Store any remaining data after the mdat for later usage */
5194 remaining_data_size = gst_adapter_available (demux->adapter);
5195 if (remaining_data_size > 0) {
5196 g_assert (demux->restoredata_buffer == NULL);
5197 demux->restoredata_buffer =
5198 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
5199 demux->restoredata_offset = demux->offset + demux->neededbytes;
5200 GST_DEBUG_OBJECT (demux,
5201 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
5202 G_GUINT64_FORMAT, remaining_data_size,
5203 demux->restoredata_offset);
5206 gst_adapter_push (demux->adapter, demux->mdatbuffer);
5207 demux->mdatbuffer = NULL;
5208 demux->offset = demux->mdatoffset;
5209 demux->neededbytes = next_entry_size (demux);
5210 demux->state = QTDEMUX_STATE_MOVIE;
5211 demux->mdatleft = gst_adapter_available (demux->adapter);
5213 GST_DEBUG_OBJECT (demux, "Carrying on normally");
5214 gst_adapter_flush (demux->adapter, demux->neededbytes);
5216 /* only go back to the mdat if there are samples to play */
5217 if (demux->got_moov && demux->first_mdat != -1
5218 && has_next_entry (demux)) {
5221 /* we need to seek back */
5222 res = qtdemux_seek_offset (demux, demux->first_mdat);
5224 demux->offset = demux->first_mdat;
5226 GST_DEBUG_OBJECT (demux, "Seek back failed");
5229 demux->offset += demux->neededbytes;
5231 demux->neededbytes = 16;
5232 demux->state = QTDEMUX_STATE_INITIAL;
5237 case QTDEMUX_STATE_BUFFER_MDAT:{
5241 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
5243 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
5244 gst_buffer_extract (buf, 0, fourcc, 4);
5245 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
5246 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
5247 if (demux->mdatbuffer)
5248 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
5250 demux->mdatbuffer = buf;
5251 demux->offset += demux->neededbytes;
5252 demux->neededbytes = 16;
5253 demux->state = QTDEMUX_STATE_INITIAL;
5254 gst_qtdemux_post_progress (demux, 1, 1);
5258 case QTDEMUX_STATE_MOVIE:{
5260 QtDemuxStream *stream = NULL;
5261 QtDemuxSample *sample;
5263 GstClockTime dts, pts, duration;
5266 GST_DEBUG_OBJECT (demux,
5267 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
5269 if (demux->fragmented) {
5270 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
5272 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
5273 /* if needed data starts within this atom,
5274 * then it should not exceed this atom */
5275 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
5276 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
5277 (_("This file is invalid and cannot be played.")),
5278 ("sample data crosses atom boundary"));
5279 ret = GST_FLOW_ERROR;
5282 demux->mdatleft -= demux->neededbytes;
5284 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
5285 /* so we are dropping more than left in this atom */
5286 demux->todrop -= demux->mdatleft;
5287 demux->neededbytes -= demux->mdatleft;
5288 demux->mdatleft = 0;
5289 /* need to resume atom parsing so we do not miss any other pieces */
5290 demux->state = QTDEMUX_STATE_INITIAL;
5291 demux->neededbytes = 16;
5293 /* check if there was any stored post mdat data from previous buffers */
5294 if (demux->restoredata_buffer) {
5295 g_assert (gst_adapter_available (demux->adapter) == 0);
5297 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
5298 demux->restoredata_buffer = NULL;
5299 demux->offset = demux->restoredata_offset;
5306 if (demux->todrop) {
5307 GST_LOG_OBJECT (demux, "Dropping %d bytes", demux->todrop);
5308 gst_adapter_flush (demux->adapter, demux->todrop);
5309 demux->neededbytes -= demux->todrop;
5310 demux->offset += demux->todrop;
5314 /* initial newsegment sent here after having added pads,
5315 * possible others in sink_event */
5316 if (G_UNLIKELY (demux->pending_newsegment)) {
5317 gst_qtdemux_push_pending_newsegment (demux);
5318 /* clear to send tags on all streams */
5319 for (i = 0; i < demux->n_streams; i++) {
5320 stream = demux->streams[i];
5321 gst_qtdemux_push_tags (demux, stream);
5322 if (stream->sparse) {
5323 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
5324 gst_pad_push_event (stream->pad,
5325 gst_event_new_gap (stream->segment.position,
5326 GST_CLOCK_TIME_NONE));
5331 /* Figure out which stream this packet belongs to */
5332 for (i = 0; i < demux->n_streams; i++) {
5333 stream = demux->streams[i];
5334 if (stream->sample_index >= stream->n_samples)
5336 GST_LOG_OBJECT (demux,
5337 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
5338 " / size:%d)", i, stream->sample_index,
5339 stream->samples[stream->sample_index].offset,
5340 stream->samples[stream->sample_index].size);
5342 if (stream->samples[stream->sample_index].offset == demux->offset)
5346 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
5347 goto unknown_stream;
5349 if (stream->new_caps) {
5350 gst_qtdemux_configure_stream (demux, stream);
5353 /* Put data in a buffer, set timestamps, caps, ... */
5354 sample = &stream->samples[stream->sample_index];
5356 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
5357 outbuf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
5358 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
5359 GST_FOURCC_ARGS (stream->fourcc));
5361 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
5363 dts = QTSAMPLE_DTS (stream, sample);
5364 pts = QTSAMPLE_PTS (stream, sample);
5365 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
5366 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5368 /* check for segment end */
5369 if (G_UNLIKELY (demux->segment.stop != -1
5370 && demux->segment.stop <= pts && stream->on_keyframe)) {
5371 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
5372 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
5374 /* check if all streams are eos */
5376 for (i = 0; i < demux->n_streams; i++) {
5377 if (!STREAM_IS_EOS (demux->streams[i])) {
5383 if (ret == GST_FLOW_EOS) {
5384 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
5388 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
5389 dts, pts, duration, keyframe, dts, demux->offset);
5393 ret = gst_qtdemux_combine_flows (demux, ret);
5395 /* skip this data, stream is EOS */
5396 gst_adapter_flush (demux->adapter, demux->neededbytes);
5399 stream->sample_index++;
5400 stream->offset_in_sample = 0;
5402 /* update current offset and figure out size of next buffer */
5403 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
5404 demux->offset, demux->neededbytes);
5405 demux->offset += demux->neededbytes;
5406 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
5409 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
5410 if (demux->fragmented) {
5411 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
5412 /* there may be more to follow, only finish this atom */
5413 demux->todrop = demux->mdatleft;
5414 demux->neededbytes = demux->todrop;
5426 /* when buffering movie data, at least show user something is happening */
5427 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
5428 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
5429 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
5430 demux->neededbytes);
5439 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
5440 ret = GST_FLOW_ERROR;
5445 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
5451 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
5452 (NULL), ("qtdemuxer invalid state %d", demux->state));
5453 ret = GST_FLOW_ERROR;
5458 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
5459 (NULL), ("no 'moov' atom within the first 10 MB"));
5460 ret = GST_FLOW_ERROR;
5466 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
5471 query = gst_query_new_scheduling ();
5473 if (!gst_pad_peer_query (sinkpad, query)) {
5474 gst_query_unref (query);
5478 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
5479 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
5480 gst_query_unref (query);
5485 GST_DEBUG_OBJECT (sinkpad, "activating pull");
5486 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
5490 GST_DEBUG_OBJECT (sinkpad, "activating push");
5491 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
5496 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
5497 GstPadMode mode, gboolean active)
5500 GstQTDemux *demux = GST_QTDEMUX (parent);
5503 case GST_PAD_MODE_PUSH:
5504 demux->pullbased = FALSE;
5507 case GST_PAD_MODE_PULL:
5509 demux->pullbased = TRUE;
5510 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
5513 res = gst_pad_stop_task (sinkpad);
5525 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
5527 return g_malloc (items * size);
5531 qtdemux_zfree (void *opaque, void *addr)
5537 qtdemux_inflate (void *z_buffer, guint z_length, guint length)
5543 z = g_new0 (z_stream, 1);
5544 z->zalloc = qtdemux_zalloc;
5545 z->zfree = qtdemux_zfree;
5548 z->next_in = z_buffer;
5549 z->avail_in = z_length;
5551 buffer = (guint8 *) g_malloc (length);
5552 ret = inflateInit (z);
5553 while (z->avail_in > 0) {
5554 if (z->avail_out == 0) {
5556 buffer = (guint8 *) g_realloc (buffer, length);
5557 z->next_out = buffer + z->total_out;
5558 z->avail_out = 1024;
5560 ret = inflate (z, Z_SYNC_FLUSH);
5564 if (ret != Z_STREAM_END) {
5565 g_warning ("inflate() returned %d", ret);
5571 #endif /* HAVE_ZLIB */
5574 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
5578 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
5580 /* counts as header data */
5581 qtdemux->header_size += length;
5583 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
5584 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
5586 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
5592 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
5593 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
5594 if (dcom == NULL || cmvd == NULL)
5595 goto invalid_compression;
5597 method = QT_FOURCC ((guint8 *) dcom->data + 8);
5600 case GST_MAKE_FOURCC ('z', 'l', 'i', 'b'):{
5601 guint uncompressed_length;
5602 guint compressed_length;
5605 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
5606 compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12;
5607 GST_LOG ("length = %u", uncompressed_length);
5610 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
5611 compressed_length, uncompressed_length);
5613 qtdemux->moov_node_compressed = qtdemux->moov_node;
5614 qtdemux->moov_node = g_node_new (buf);
5616 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
5617 uncompressed_length);
5620 #endif /* HAVE_ZLIB */
5622 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
5623 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
5630 invalid_compression:
5632 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
5638 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
5641 while (G_UNLIKELY (buf < end)) {
5645 if (G_UNLIKELY (buf + 4 > end)) {
5646 GST_LOG_OBJECT (qtdemux, "buffer overrun");
5649 len = QT_UINT32 (buf);
5650 if (G_UNLIKELY (len == 0)) {
5651 GST_LOG_OBJECT (qtdemux, "empty container");
5654 if (G_UNLIKELY (len < 8)) {
5655 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
5658 if (G_UNLIKELY (len > (end - buf))) {
5659 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
5660 (gint) (end - buf));
5664 child = g_node_new ((guint8 *) buf);
5665 g_node_append (node, child);
5666 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
5667 qtdemux_parse_node (qtdemux, child, buf, len);
5675 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
5678 int len = QT_UINT32 (xdxt->data);
5679 guint8 *buf = xdxt->data;
5680 guint8 *end = buf + len;
5683 /* skip size and type */
5691 size = QT_UINT32 (buf);
5692 type = QT_FOURCC (buf + 4);
5694 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
5696 if (buf + size > end || size <= 0)
5702 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
5703 GST_FOURCC_ARGS (type));
5707 buffer = gst_buffer_new_and_alloc (size);
5708 gst_buffer_fill (buffer, 0, buf, size);
5709 stream->buffers = g_slist_append (stream->buffers, buffer);
5710 GST_LOG_OBJECT (qtdemux, "parsing theora header");
5713 buffer = gst_buffer_new_and_alloc (size);
5714 gst_buffer_fill (buffer, 0, buf, size);
5715 stream->buffers = g_slist_append (stream->buffers, buffer);
5716 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
5719 buffer = gst_buffer_new_and_alloc (size);
5720 gst_buffer_fill (buffer, 0, buf, size);
5721 stream->buffers = g_slist_append (stream->buffers, buffer);
5722 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
5725 GST_WARNING_OBJECT (qtdemux,
5726 "unknown theora cookie %" GST_FOURCC_FORMAT,
5727 GST_FOURCC_ARGS (type));
5736 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
5740 guint32 node_length = 0;
5741 const QtNodeType *type;
5744 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
5746 if (G_UNLIKELY (length < 8))
5747 goto not_enough_data;
5749 node_length = QT_UINT32 (buffer);
5750 fourcc = QT_FOURCC (buffer + 4);
5752 /* ignore empty nodes */
5753 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
5756 type = qtdemux_type_get (fourcc);
5758 end = buffer + length;
5760 GST_LOG_OBJECT (qtdemux,
5761 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
5762 GST_FOURCC_ARGS (fourcc), node_length, type->name);
5764 if (node_length > length)
5765 goto broken_atom_size;
5767 if (type->flags & QT_FLAG_CONTAINER) {
5768 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
5773 if (node_length < 20) {
5774 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
5777 GST_DEBUG_OBJECT (qtdemux,
5778 "parsing stsd (sample table, sample description) atom");
5779 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
5780 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
5790 /* also read alac (or whatever) in stead of mp4a in the following,
5791 * since a similar layout is used in other cases as well */
5792 if (fourcc == FOURCC_mp4a)
5797 /* There are two things we might encounter here: a true mp4a atom, and
5798 an mp4a entry in an stsd atom. The latter is what we're interested
5799 in, and it looks like an atom, but isn't really one. The true mp4a
5800 atom is short, so we detect it based on length here. */
5801 if (length < min_size) {
5802 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
5803 GST_FOURCC_ARGS (fourcc));
5807 /* 'version' here is the sound sample description version. Types 0 and
5808 1 are documented in the QTFF reference, but type 2 is not: it's
5809 described in Apple header files instead (struct SoundDescriptionV2
5811 version = QT_UINT16 (buffer + 16);
5813 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
5814 GST_FOURCC_ARGS (fourcc), version);
5816 /* parse any esds descriptors */
5828 GST_WARNING_OBJECT (qtdemux,
5829 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
5830 GST_FOURCC_ARGS (fourcc), version);
5835 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
5852 /* codec_data is contained inside these atoms, which all have
5853 * the same format. */
5855 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
5856 GST_FOURCC_ARGS (fourcc));
5857 version = QT_UINT32 (buffer + 16);
5858 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
5859 if (1 || version == 0x00000000) {
5860 buf = buffer + 0x32;
5862 /* FIXME Quicktime uses PASCAL string while
5863 * the iso format uses C strings. Check the file
5864 * type before attempting to parse the string here. */
5865 tlen = QT_UINT8 (buf);
5866 GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
5868 GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
5869 /* the string has a reserved space of 32 bytes so skip
5870 * the remaining 31 */
5872 buf += 4; /* and 4 bytes reserved */
5874 GST_MEMDUMP_OBJECT (qtdemux, "mp4v", buf, end - buf);
5876 qtdemux_parse_container (qtdemux, node, buf, end);
5882 GST_MEMDUMP_OBJECT (qtdemux, "H264", buffer, end - buffer);
5883 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
5888 GST_MEMDUMP_OBJECT (qtdemux, "avc1", buffer, end - buffer);
5889 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
5894 GST_MEMDUMP_OBJECT (qtdemux, "avc3", buffer, end - buffer);
5895 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
5900 GST_MEMDUMP_OBJECT (qtdemux, "H265", buffer, end - buffer);
5901 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
5906 GST_MEMDUMP_OBJECT (qtdemux, "hvc1", buffer, end - buffer);
5907 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
5912 GST_MEMDUMP_OBJECT (qtdemux, "hev1", buffer, end - buffer);
5913 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
5918 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
5923 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
5924 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
5929 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
5930 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
5931 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
5939 version = QT_UINT32 (buffer + 12);
5940 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
5947 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
5952 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
5957 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
5962 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
5966 if (!strcmp (type->name, "unknown"))
5967 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
5971 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
5972 GST_FOURCC_ARGS (fourcc));
5978 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5979 (_("This file is corrupt and cannot be played.")),
5980 ("Not enough data for an atom header, got only %u bytes", length));
5985 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5986 (_("This file is corrupt and cannot be played.")),
5987 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
5988 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
5995 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
5999 guint32 child_fourcc;
6001 for (child = g_node_first_child (node); child;
6002 child = g_node_next_sibling (child)) {
6003 buffer = (guint8 *) child->data;
6005 child_fourcc = QT_FOURCC (buffer + 4);
6007 if (G_UNLIKELY (child_fourcc == fourcc)) {
6015 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
6016 GstByteReader * parser)
6020 guint32 child_fourcc, child_len;
6022 for (child = g_node_first_child (node); child;
6023 child = g_node_next_sibling (child)) {
6024 buffer = (guint8 *) child->data;
6026 child_len = QT_UINT32 (buffer);
6027 child_fourcc = QT_FOURCC (buffer + 4);
6029 if (G_UNLIKELY (child_fourcc == fourcc)) {
6030 if (G_UNLIKELY (child_len < (4 + 4)))
6032 /* FIXME: must verify if atom length < parent atom length */
6033 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
6041 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
6042 GstByteReader * parser)
6046 guint32 child_fourcc, child_len;
6048 for (child = g_node_next_sibling (node); child;
6049 child = g_node_next_sibling (child)) {
6050 buffer = (guint8 *) child->data;
6052 child_fourcc = QT_FOURCC (buffer + 4);
6054 if (child_fourcc == fourcc) {
6056 child_len = QT_UINT32 (buffer);
6057 if (G_UNLIKELY (child_len < (4 + 4)))
6059 /* FIXME: must verify if atom length < parent atom length */
6060 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
6069 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
6071 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
6075 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
6077 /* FIXME: This can only reliably work if demuxers have a
6078 * separate streaming thread per srcpad. This should be
6079 * done in a demuxer base class, which integrates parts
6082 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
6087 query = gst_query_new_allocation (stream->caps, FALSE);
6089 if (!gst_pad_peer_query (stream->pad, query)) {
6090 /* not a problem, just debug a little */
6091 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
6094 if (stream->allocator)
6095 gst_object_unref (stream->allocator);
6097 if (gst_query_get_n_allocation_params (query) > 0) {
6098 /* try the allocator */
6099 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
6101 stream->use_allocator = TRUE;
6103 stream->allocator = NULL;
6104 gst_allocation_params_init (&stream->params);
6105 stream->use_allocator = FALSE;
6107 gst_query_unref (query);
6112 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
6114 if (stream->subtype == FOURCC_vide) {
6115 /* fps is calculated base on the duration of the average framerate since
6116 * qt does not have a fixed framerate. */
6117 if ((stream->n_samples == 1) && (stream->first_duration == 0)) {
6122 if (stream->duration == 0 || stream->n_samples < 2) {
6123 stream->fps_n = stream->timescale;
6126 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
6127 /* stream->duration is guint64, timescale, n_samples are guint32 */
6128 GstClockTime avg_duration =
6129 gst_util_uint64_scale_round (stream->duration -
6130 stream->first_duration, GST_SECOND,
6131 (guint64) (stream->timescale) * (stream->n_samples - 1));
6133 GST_LOG_OBJECT (qtdemux,
6134 "Calculating avg sample duration based on stream duration %"
6136 " minus first sample %u, leaving %d samples gives %"
6137 GST_TIME_FORMAT, stream->duration, stream->first_duration,
6138 stream->n_samples - 1, GST_TIME_ARGS (avg_duration));
6140 gst_video_guess_framerate (avg_duration, &stream->fps_n,
6143 GST_DEBUG_OBJECT (qtdemux,
6144 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
6145 stream->timescale, stream->fps_n, stream->fps_d);
6149 stream->caps = gst_caps_make_writable (stream->caps);
6151 gst_caps_set_simple (stream->caps,
6152 "width", G_TYPE_INT, stream->width,
6153 "height", G_TYPE_INT, stream->height,
6154 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
6156 /* calculate pixel-aspect-ratio using display width and height */
6157 GST_DEBUG_OBJECT (qtdemux,
6158 "video size %dx%d, target display size %dx%d", stream->width,
6159 stream->height, stream->display_width, stream->display_height);
6161 if (stream->display_width > 0 && stream->display_height > 0 &&
6162 stream->width > 0 && stream->height > 0) {
6165 /* calculate the pixel aspect ratio using the display and pixel w/h */
6166 n = stream->display_width * stream->height;
6167 d = stream->display_height * stream->width;
6170 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
6171 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
6172 GST_TYPE_FRACTION, n, d, NULL);
6175 /* qt file might have pasp atom */
6176 if (stream->par_w > 0 && stream->par_h > 0) {
6177 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
6178 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
6179 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
6182 } else if (stream->subtype == FOURCC_soun) {
6184 stream->caps = gst_caps_make_writable (stream->caps);
6185 if (stream->rate > 0)
6186 gst_caps_set_simple (stream->caps,
6187 "rate", G_TYPE_INT, (int) stream->rate, NULL);
6188 if (stream->n_channels > 0)
6189 gst_caps_set_simple (stream->caps,
6190 "channels", G_TYPE_INT, stream->n_channels, NULL);
6191 if (stream->n_channels > 2) {
6192 /* FIXME: Need to parse the 'chan' atom to get channel layouts
6193 * correctly; this is just the minimum we can do - assume
6194 * we don't actually have any channel positions. */
6195 gst_caps_set_simple (stream->caps,
6196 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
6202 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
6203 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
6204 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
6205 gst_pad_set_active (stream->pad, TRUE);
6207 gst_pad_use_fixed_caps (stream->pad);
6209 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
6210 if (stream->new_stream) {
6213 GstStreamFlags stream_flags;
6216 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
6219 if (gst_event_parse_group_id (event, &qtdemux->group_id))
6220 qtdemux->have_group_id = TRUE;
6222 qtdemux->have_group_id = FALSE;
6223 gst_event_unref (event);
6224 } else if (!qtdemux->have_group_id) {
6225 qtdemux->have_group_id = TRUE;
6226 qtdemux->group_id = gst_util_group_id_next ();
6229 stream->new_stream = FALSE;
6231 gst_pad_create_stream_id_printf (stream->pad,
6232 GST_ELEMENT_CAST (qtdemux), "%03u", stream->track_id);
6233 event = gst_event_new_stream_start (stream_id);
6234 if (qtdemux->have_group_id)
6235 gst_event_set_group_id (event, qtdemux->group_id);
6236 stream_flags = GST_STREAM_FLAG_NONE;
6237 if (stream->disabled)
6238 stream_flags |= GST_STREAM_FLAG_UNSELECT;
6240 stream_flags |= GST_STREAM_FLAG_SPARSE;
6241 gst_event_set_stream_flags (event, stream_flags);
6242 gst_pad_push_event (stream->pad, event);
6245 gst_pad_set_caps (stream->pad, stream->caps);
6246 stream->new_caps = FALSE;
6252 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
6253 QtDemuxStream * stream, GstTagList * list)
6255 /* consistent default for push based mode */
6256 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
6258 if (stream->subtype == FOURCC_vide) {
6259 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
6262 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
6265 gst_qtdemux_configure_stream (qtdemux, stream);
6266 qtdemux->n_video_streams++;
6267 } else if (stream->subtype == FOURCC_soun) {
6268 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
6271 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
6273 gst_qtdemux_configure_stream (qtdemux, stream);
6274 qtdemux->n_audio_streams++;
6275 } else if (stream->subtype == FOURCC_strm) {
6276 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
6277 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
6278 || stream->subtype == FOURCC_sbtl) {
6279 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
6282 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
6284 gst_qtdemux_configure_stream (qtdemux, stream);
6285 qtdemux->n_sub_streams++;
6286 } else if (stream->caps) {
6287 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
6290 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
6292 gst_qtdemux_configure_stream (qtdemux, stream);
6293 qtdemux->n_video_streams++;
6295 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
6300 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
6301 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
6302 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
6303 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
6305 if (stream->pending_tags)
6306 gst_tag_list_unref (stream->pending_tags);
6307 stream->pending_tags = list;
6308 /* global tags go on each pad anyway */
6309 stream->send_global_tags = TRUE;
6315 /* find next atom with @fourcc starting at @offset */
6316 static GstFlowReturn
6317 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
6318 guint64 * length, guint32 fourcc)
6324 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
6325 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
6331 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
6332 if (G_UNLIKELY (ret != GST_FLOW_OK))
6334 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
6337 gst_buffer_unref (buf);
6340 gst_buffer_map (buf, &map, GST_MAP_READ);
6341 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
6342 gst_buffer_unmap (buf, &map);
6343 gst_buffer_unref (buf);
6345 if (G_UNLIKELY (*length == 0)) {
6346 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
6347 ret = GST_FLOW_ERROR;
6351 if (lfourcc == fourcc) {
6352 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
6356 GST_LOG_OBJECT (qtdemux,
6357 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
6358 GST_FOURCC_ARGS (fourcc), *offset);
6367 /* might simply have had last one */
6368 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
6373 /* should only do something in pull mode */
6374 /* call with OBJECT lock */
6375 static GstFlowReturn
6376 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
6378 guint64 length, offset;
6379 GstBuffer *buf = NULL;
6380 GstFlowReturn ret = GST_FLOW_OK;
6381 GstFlowReturn res = GST_FLOW_OK;
6384 offset = qtdemux->moof_offset;
6385 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
6388 GST_DEBUG_OBJECT (qtdemux, "no next moof");
6389 return GST_FLOW_EOS;
6392 /* best not do pull etc with lock held */
6393 GST_OBJECT_UNLOCK (qtdemux);
6395 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
6396 if (ret != GST_FLOW_OK)
6399 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
6400 if (G_UNLIKELY (ret != GST_FLOW_OK))
6402 gst_buffer_map (buf, &map, GST_MAP_READ);
6403 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
6404 gst_buffer_unmap (buf, &map);
6405 gst_buffer_unref (buf);
6410 gst_buffer_unmap (buf, &map);
6411 gst_buffer_unref (buf);
6415 /* look for next moof */
6416 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
6417 if (G_UNLIKELY (ret != GST_FLOW_OK))
6421 GST_OBJECT_LOCK (qtdemux);
6423 qtdemux->moof_offset = offset;
6429 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
6431 res = GST_FLOW_ERROR;
6436 /* maybe upstream temporarily flushing */
6437 if (ret != GST_FLOW_FLUSHING) {
6438 GST_DEBUG_OBJECT (qtdemux, "no next moof");
6441 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
6442 /* resume at current position next time */
6449 /* initialise bytereaders for stbl sub-atoms */
6451 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
6453 stream->stbl_index = -1; /* no samples have yet been parsed */
6454 stream->sample_index = -1;
6456 /* time-to-sample atom */
6457 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
6460 /* copy atom data into a new buffer for later use */
6461 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
6463 /* skip version + flags */
6464 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
6465 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
6467 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
6469 /* make sure there's enough data */
6470 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
6471 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
6472 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
6473 stream->n_sample_times);
6474 if (!stream->n_sample_times)
6478 /* sync sample atom */
6479 stream->stps_present = FALSE;
6480 if ((stream->stss_present =
6481 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
6482 &stream->stss) ? TRUE : FALSE) == TRUE) {
6483 /* copy atom data into a new buffer for later use */
6484 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
6486 /* skip version + flags */
6487 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
6488 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
6491 if (stream->n_sample_syncs) {
6492 /* make sure there's enough data */
6493 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
6497 /* partial sync sample atom */
6498 if ((stream->stps_present =
6499 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
6500 &stream->stps) ? TRUE : FALSE) == TRUE) {
6501 /* copy atom data into a new buffer for later use */
6502 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
6504 /* skip version + flags */
6505 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
6506 !gst_byte_reader_get_uint32_be (&stream->stps,
6507 &stream->n_sample_partial_syncs))
6510 /* if there are no entries, the stss table contains the real
6512 if (stream->n_sample_partial_syncs) {
6513 /* make sure there's enough data */
6514 if (!qt_atom_parser_has_chunks (&stream->stps,
6515 stream->n_sample_partial_syncs, 4))
6522 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
6525 /* copy atom data into a new buffer for later use */
6526 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
6528 /* skip version + flags */
6529 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
6530 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
6533 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
6536 if (!stream->n_samples)
6539 /* sample-to-chunk atom */
6540 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
6543 /* copy atom data into a new buffer for later use */
6544 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
6546 /* skip version + flags */
6547 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
6548 !gst_byte_reader_get_uint32_be (&stream->stsc,
6549 &stream->n_samples_per_chunk))
6552 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
6553 stream->n_samples_per_chunk);
6555 /* make sure there's enough data */
6556 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
6562 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
6563 stream->co_size = sizeof (guint32);
6564 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
6566 stream->co_size = sizeof (guint64);
6570 /* copy atom data into a new buffer for later use */
6571 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
6573 /* skip version + flags */
6574 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
6577 /* chunks_are_samples == TRUE means treat chunks as samples */
6578 stream->chunks_are_samples = stream->sample_size && !stream->sampled;
6579 if (stream->chunks_are_samples) {
6580 /* treat chunks as samples */
6581 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
6584 /* skip number of entries */
6585 if (!gst_byte_reader_skip (&stream->stco, 4))
6588 /* make sure there are enough data in the stsz atom */
6589 if (!stream->sample_size) {
6590 /* different sizes for each sample */
6591 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
6596 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
6597 stream->n_samples, (guint) sizeof (QtDemuxSample),
6598 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
6600 if (stream->n_samples >=
6601 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
6602 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
6603 "be larger than %uMB (broken file?)", stream->n_samples,
6604 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
6608 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
6609 if (!stream->samples) {
6610 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
6616 /* composition time-to-sample */
6617 if ((stream->ctts_present =
6618 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
6619 &stream->ctts) ? TRUE : FALSE) == TRUE) {
6620 /* copy atom data into a new buffer for later use */
6621 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
6623 /* skip version + flags */
6624 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
6625 || !gst_byte_reader_get_uint32_be (&stream->ctts,
6626 &stream->n_composition_times))
6629 /* make sure there's enough data */
6630 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
6639 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
6640 (_("This file is corrupt and cannot be played.")), (NULL));
6645 gst_qtdemux_stbl_free (stream);
6646 if (!qtdemux->fragmented) {
6647 /* not quite good */
6648 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
6651 /* may pick up samples elsewhere */
6657 /* collect samples from the next sample to be parsed up to sample @n for @stream
6658 * by reading the info from @stbl
6660 * This code can be executed from both the streaming thread and the seeking
6661 * thread so it takes the object lock to protect itself
6664 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
6667 QtDemuxSample *samples, *first, *cur, *last;
6668 guint32 n_samples_per_chunk;
6671 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
6672 GST_FOURCC_FORMAT ", pad %s", GST_FOURCC_ARGS (stream->fourcc),
6673 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
6675 n_samples = stream->n_samples;
6678 goto out_of_samples;
6680 GST_OBJECT_LOCK (qtdemux);
6681 if (n <= stream->stbl_index)
6682 goto already_parsed;
6684 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
6686 if (!stream->stsz.data) {
6687 /* so we already parsed and passed all the moov samples;
6688 * onto fragmented ones */
6689 g_assert (qtdemux->fragmented);
6693 /* pointer to the sample table */
6694 samples = stream->samples;
6696 /* starts from -1, moves to the next sample index to parse */
6697 stream->stbl_index++;
6699 /* keep track of the first and last sample to fill */
6700 first = &samples[stream->stbl_index];
6703 if (!stream->chunks_are_samples) {
6704 /* set the sample sizes */
6705 if (stream->sample_size == 0) {
6706 /* different sizes for each sample */
6707 for (cur = first; cur <= last; cur++) {
6708 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
6709 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
6710 (guint) (cur - samples), cur->size);
6713 /* samples have the same size */
6714 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
6715 for (cur = first; cur <= last; cur++)
6716 cur->size = stream->sample_size;
6720 n_samples_per_chunk = stream->n_samples_per_chunk;
6723 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
6726 if (stream->stsc_chunk_index >= stream->last_chunk
6727 || stream->stsc_chunk_index < stream->first_chunk) {
6728 stream->first_chunk =
6729 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
6730 stream->samples_per_chunk =
6731 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
6732 gst_byte_reader_skip_unchecked (&stream->stsc, 4);
6734 /* chunk numbers are counted from 1 it seems */
6735 if (G_UNLIKELY (stream->first_chunk == 0))
6738 --stream->first_chunk;
6740 /* the last chunk of each entry is calculated by taking the first chunk
6741 * of the next entry; except if there is no next, where we fake it with
6743 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
6744 stream->last_chunk = G_MAXUINT32;
6746 stream->last_chunk =
6747 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
6748 if (G_UNLIKELY (stream->last_chunk == 0))
6751 --stream->last_chunk;
6754 GST_LOG_OBJECT (qtdemux,
6755 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
6756 stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
6758 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
6761 if (stream->last_chunk != G_MAXUINT32) {
6762 if (!qt_atom_parser_peek_sub (&stream->stco,
6763 stream->first_chunk * stream->co_size,
6764 (stream->last_chunk - stream->first_chunk) * stream->co_size,
6769 stream->co_chunk = stream->stco;
6770 if (!gst_byte_reader_skip (&stream->co_chunk,
6771 stream->first_chunk * stream->co_size))
6775 stream->stsc_chunk_index = stream->first_chunk;
6778 last_chunk = stream->last_chunk;
6780 if (stream->chunks_are_samples) {
6781 cur = &samples[stream->stsc_chunk_index];
6783 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
6786 stream->stsc_chunk_index = j;
6791 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
6794 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
6795 "%" G_GUINT64_FORMAT, j, cur->offset);
6797 if (stream->samples_per_frame * stream->bytes_per_frame) {
6799 (stream->samples_per_chunk * stream->n_channels) /
6800 stream->samples_per_frame * stream->bytes_per_frame;
6802 cur->size = stream->samples_per_chunk;
6805 GST_DEBUG_OBJECT (qtdemux,
6806 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
6807 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
6808 stream->stco_sample_index)), cur->size);
6810 cur->timestamp = stream->stco_sample_index;
6811 cur->duration = stream->samples_per_chunk;
6812 cur->keyframe = TRUE;
6815 stream->stco_sample_index += stream->samples_per_chunk;
6817 stream->stsc_chunk_index = j;
6819 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
6820 guint32 samples_per_chunk;
6821 guint64 chunk_offset;
6823 if (!stream->stsc_sample_index
6824 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
6825 &stream->chunk_offset))
6828 samples_per_chunk = stream->samples_per_chunk;
6829 chunk_offset = stream->chunk_offset;
6831 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
6832 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
6833 G_GUINT64_FORMAT " and size %d",
6834 (guint) (cur - samples), chunk_offset, cur->size);
6836 cur->offset = chunk_offset;
6837 chunk_offset += cur->size;
6840 if (G_UNLIKELY (cur > last)) {
6842 stream->stsc_sample_index = k + 1;
6843 stream->chunk_offset = chunk_offset;
6844 stream->stsc_chunk_index = j;
6848 stream->stsc_sample_index = 0;
6850 stream->stsc_chunk_index = j;
6852 stream->stsc_index++;
6855 if (stream->chunks_are_samples)
6859 guint32 n_sample_times;
6861 n_sample_times = stream->n_sample_times;
6864 for (i = stream->stts_index; i < n_sample_times; i++) {
6865 guint32 stts_samples;
6866 gint32 stts_duration;
6869 if (stream->stts_sample_index >= stream->stts_samples
6870 || !stream->stts_sample_index) {
6872 stream->stts_samples =
6873 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
6874 stream->stts_duration =
6875 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
6877 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
6878 i, stream->stts_samples, stream->stts_duration);
6880 stream->stts_sample_index = 0;
6883 stts_samples = stream->stts_samples;
6884 stts_duration = stream->stts_duration;
6885 stts_time = stream->stts_time;
6887 for (j = stream->stts_sample_index; j < stts_samples; j++) {
6888 GST_DEBUG_OBJECT (qtdemux,
6889 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
6890 (guint) (cur - samples), j,
6891 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
6893 cur->timestamp = stts_time;
6894 cur->duration = stts_duration;
6896 /* avoid 32-bit wrap-around,
6897 * but still mind possible 'negative' duration */
6898 stts_time += (gint64) stts_duration;
6901 if (G_UNLIKELY (cur > last)) {
6903 stream->stts_time = stts_time;
6904 stream->stts_sample_index = j + 1;
6908 stream->stts_sample_index = 0;
6909 stream->stts_time = stts_time;
6910 stream->stts_index++;
6912 /* fill up empty timestamps with the last timestamp, this can happen when
6913 * the last samples do not decode and so we don't have timestamps for them.
6914 * We however look at the last timestamp to estimate the track length so we
6915 * need something in here. */
6916 for (; cur < last; cur++) {
6917 GST_DEBUG_OBJECT (qtdemux,
6918 "fill sample %d: timestamp %" GST_TIME_FORMAT,
6919 (guint) (cur - samples),
6920 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
6921 cur->timestamp = stream->stts_time;
6927 /* sample sync, can be NULL */
6928 if (stream->stss_present == TRUE) {
6929 guint32 n_sample_syncs;
6931 n_sample_syncs = stream->n_sample_syncs;
6933 if (!n_sample_syncs) {
6934 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
6935 stream->all_keyframe = TRUE;
6937 for (i = stream->stss_index; i < n_sample_syncs; i++) {
6938 /* note that the first sample is index 1, not 0 */
6941 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
6943 if (G_LIKELY (index > 0 && index <= n_samples)) {
6945 samples[index].keyframe = TRUE;
6946 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
6947 /* and exit if we have enough samples */
6948 if (G_UNLIKELY (index >= n)) {
6955 stream->stss_index = i;
6958 /* stps marks partial sync frames like open GOP I-Frames */
6959 if (stream->stps_present == TRUE) {
6960 guint32 n_sample_partial_syncs;
6962 n_sample_partial_syncs = stream->n_sample_partial_syncs;
6964 /* if there are no entries, the stss table contains the real
6966 if (n_sample_partial_syncs) {
6967 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
6968 /* note that the first sample is index 1, not 0 */
6971 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
6973 if (G_LIKELY (index > 0 && index <= n_samples)) {
6975 samples[index].keyframe = TRUE;
6976 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
6977 /* and exit if we have enough samples */
6978 if (G_UNLIKELY (index >= n)) {
6985 stream->stps_index = i;
6989 /* no stss, all samples are keyframes */
6990 stream->all_keyframe = TRUE;
6991 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
6996 /* composition time to sample */
6997 if (stream->ctts_present == TRUE) {
6998 guint32 n_composition_times;
7000 gint32 ctts_soffset;
7002 /* Fill in the pts_offsets */
7004 n_composition_times = stream->n_composition_times;
7006 for (i = stream->ctts_index; i < n_composition_times; i++) {
7007 if (stream->ctts_sample_index >= stream->ctts_count
7008 || !stream->ctts_sample_index) {
7009 stream->ctts_count =
7010 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
7011 stream->ctts_soffset =
7012 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
7013 stream->ctts_sample_index = 0;
7016 ctts_count = stream->ctts_count;
7017 ctts_soffset = stream->ctts_soffset;
7019 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
7020 cur->pts_offset = ctts_soffset;
7023 if (G_UNLIKELY (cur > last)) {
7025 stream->ctts_sample_index = j + 1;
7029 stream->ctts_sample_index = 0;
7030 stream->ctts_index++;
7034 stream->stbl_index = n;
7035 /* if index has been completely parsed, free data that is no-longer needed */
7036 if (n + 1 == stream->n_samples) {
7037 gst_qtdemux_stbl_free (stream);
7038 GST_DEBUG_OBJECT (qtdemux,
7039 "parsed all available samples; checking for more");
7040 while (n + 1 == stream->n_samples)
7041 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
7044 GST_OBJECT_UNLOCK (qtdemux);
7051 GST_LOG_OBJECT (qtdemux,
7052 "Tried to parse up to sample %u but this sample has already been parsed",
7054 /* if fragmented, there may be more */
7055 if (qtdemux->fragmented && n == stream->stbl_index)
7057 GST_OBJECT_UNLOCK (qtdemux);
7063 GST_LOG_OBJECT (qtdemux,
7064 "Tried to parse up to sample %u but there are only %u samples", n + 1,
7066 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7067 (_("This file is corrupt and cannot be played.")), (NULL));
7072 GST_OBJECT_UNLOCK (qtdemux);
7073 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7074 (_("This file is corrupt and cannot be played.")), (NULL));
7079 /* collect all segment info for @stream.
7082 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
7087 /* parse and prepare segment info from the edit list */
7088 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
7089 stream->n_segments = 0;
7090 stream->segments = NULL;
7091 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
7099 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
7100 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
7103 buffer = elst->data;
7105 n_segments = QT_UINT32 (buffer + 12);
7107 /* we might allocate a bit too much, at least allocate 1 segment */
7108 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
7110 /* segments always start from 0 */
7114 for (i = 0; i < n_segments; i++) {
7117 QtDemuxSegment *segment;
7120 media_time = QT_UINT32 (buffer + 20 + i * 12);
7121 duration = QT_UINT32 (buffer + 16 + i * 12);
7123 segment = &stream->segments[count++];
7125 /* time and duration expressed in global timescale */
7126 segment->time = stime;
7127 /* add non scaled values so we don't cause roundoff errors */
7129 stime = QTTIME_TO_GSTTIME (qtdemux, time);
7130 segment->stop_time = stime;
7131 segment->duration = stime - segment->time;
7133 segment->trak_media_start = media_time;
7134 /* media_time expressed in stream timescale */
7135 if (media_time != G_MAXUINT32) {
7136 segment->media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
7137 segment->media_stop = segment->media_start + segment->duration;
7139 segment->media_start = GST_CLOCK_TIME_NONE;
7140 segment->media_stop = GST_CLOCK_TIME_NONE;
7142 rate_int = GST_READ_UINT32_BE (buffer + 24 + i * 12);
7144 if (rate_int <= 1) {
7145 /* 0 is not allowed, some programs write 1 instead of the floating point
7147 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
7151 segment->rate = rate_int / 65536.0;
7154 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
7155 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
7156 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
7157 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
7158 i, GST_TIME_ARGS (segment->time),
7159 GST_TIME_ARGS (segment->duration),
7160 GST_TIME_ARGS (segment->media_start), media_time,
7161 GST_TIME_ARGS (segment->media_stop),
7162 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
7164 if (segment->stop_time > qtdemux->segment.stop) {
7165 GST_WARNING_OBJECT (qtdemux, "Segment %d "
7166 " extends to %" GST_TIME_FORMAT
7167 " past the end of the file duration %" GST_TIME_FORMAT
7168 " it will be truncated", i, GST_TIME_ARGS (segment->stop_time),
7169 GST_TIME_ARGS (qtdemux->segment.stop));
7170 qtdemux->segment.stop = segment->stop_time;
7173 GST_DEBUG_OBJECT (qtdemux, "found %d segments", count);
7174 stream->n_segments = count;
7178 /* push based does not handle segments, so act accordingly here,
7179 * and warn if applicable */
7180 if (!qtdemux->pullbased) {
7181 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
7182 /* remove and use default one below, we stream like it anyway */
7183 g_free (stream->segments);
7184 stream->segments = NULL;
7185 stream->n_segments = 0;
7188 /* no segments, create one to play the complete trak */
7189 if (stream->n_segments == 0) {
7190 GstClockTime stream_duration =
7191 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
7193 if (stream->segments == NULL)
7194 stream->segments = g_new (QtDemuxSegment, 1);
7196 /* represent unknown our way */
7197 if (stream_duration == 0)
7198 stream_duration = GST_CLOCK_TIME_NONE;
7200 stream->segments[0].time = 0;
7201 stream->segments[0].stop_time = stream_duration;
7202 stream->segments[0].duration = stream_duration;
7203 stream->segments[0].media_start = 0;
7204 stream->segments[0].media_stop = stream_duration;
7205 stream->segments[0].rate = 1.0;
7206 stream->segments[0].trak_media_start = 0;
7208 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
7209 GST_TIME_ARGS (stream_duration));
7210 stream->n_segments = 1;
7211 stream->dummy_segment = TRUE;
7213 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
7219 * Parses the stsd atom of a svq3 trak looking for
7220 * the SMI and gama atoms.
7223 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
7224 guint8 ** gamma, GstBuffer ** seqh)
7226 guint8 *_gamma = NULL;
7227 GstBuffer *_seqh = NULL;
7228 guint8 *stsd_data = stsd->data;
7229 guint32 length = QT_UINT32 (stsd_data);
7233 GST_WARNING_OBJECT (qtdemux, "stsd too short");
7239 version = QT_UINT16 (stsd_data);
7244 while (length > 8) {
7245 guint32 fourcc, size;
7247 size = QT_UINT32 (stsd_data);
7248 fourcc = QT_FOURCC (stsd_data + 4);
7249 data = stsd_data + 8;
7252 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
7253 "svq3 atom parsing");
7262 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
7263 " for gama atom, expected 12", size);
7268 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
7270 if (_seqh != NULL) {
7271 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
7272 " found, ignoring");
7274 seqh_size = QT_UINT32 (data + 4);
7275 if (seqh_size > 0) {
7276 _seqh = gst_buffer_new_and_alloc (seqh_size);
7277 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
7284 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
7285 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
7289 if (size <= length) {
7295 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
7298 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
7299 G_GUINT16_FORMAT, version);
7310 gst_buffer_unref (_seqh);
7315 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
7322 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
7323 * atom that might contain a 'data' atom with the rtsp uri.
7324 * This case was reported in bug #597497, some info about
7325 * the hndl atom can be found in TN1195
7327 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
7328 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
7331 guint32 dref_num_entries = 0;
7332 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
7333 gst_byte_reader_skip (&dref, 4) &&
7334 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
7337 /* search dref entries for hndl atom */
7338 for (i = 0; i < dref_num_entries; i++) {
7339 guint32 size = 0, type;
7340 guint8 string_len = 0;
7341 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
7342 qt_atom_parser_get_fourcc (&dref, &type)) {
7343 if (type == FOURCC_hndl) {
7344 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
7346 /* skip data reference handle bytes and the
7347 * following pascal string and some extra 4
7348 * bytes I have no idea what are */
7349 if (!gst_byte_reader_skip (&dref, 4) ||
7350 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
7351 !gst_byte_reader_skip (&dref, string_len + 4)) {
7352 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
7356 /* iterate over the atoms to find the data atom */
7357 while (gst_byte_reader_get_remaining (&dref) >= 8) {
7361 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
7362 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
7363 if (atom_type == FOURCC_data) {
7364 const guint8 *uri_aux = NULL;
7366 /* found the data atom that might contain the rtsp uri */
7367 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
7368 "hndl atom, interpreting it as an URI");
7369 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
7371 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
7372 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
7374 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
7375 "didn't contain a rtsp address");
7377 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
7382 /* skipping to the next entry */
7383 if (!gst_byte_reader_skip (&dref, atom_size - 8))
7386 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
7393 /* skip to the next entry */
7394 if (!gst_byte_reader_skip (&dref, size - 8))
7397 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
7400 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
7406 #define AMR_NB_ALL_MODES 0x81ff
7407 #define AMR_WB_ALL_MODES 0x83ff
7409 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
7411 /* The 'damr' atom is of the form:
7413 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
7414 * 32 b 8 b 16 b 8 b 8 b
7416 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
7417 * represents the highest mode used in the stream (and thus the maximum
7418 * bitrate), with a couple of special cases as seen below.
7421 /* Map of frame type ID -> bitrate */
7422 static const guint nb_bitrates[] = {
7423 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
7425 static const guint wb_bitrates[] = {
7426 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
7432 gst_buffer_map (buf, &map, GST_MAP_READ);
7434 if (map.size != 0x11) {
7435 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
7439 if (QT_FOURCC (map.data + 4) != GST_MAKE_FOURCC ('d', 'a', 'm', 'r')) {
7440 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
7441 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
7445 mode_set = QT_UINT16 (map.data + 13);
7447 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
7448 max_mode = 7 + (wb ? 1 : 0);
7450 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
7451 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
7453 if (max_mode == -1) {
7454 GST_DEBUG ("No mode indication was found (mode set) = %x",
7459 gst_buffer_unmap (buf, &map);
7460 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
7463 gst_buffer_unmap (buf, &map);
7468 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
7469 GstByteReader * reader, guint32 * matrix, const gchar * atom)
7472 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
7478 if (gst_byte_reader_get_remaining (reader) < 36)
7481 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
7482 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
7483 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
7484 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
7485 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
7486 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
7487 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
7488 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
7489 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
7491 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
7492 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
7493 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
7495 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
7496 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
7498 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
7499 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
7506 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
7507 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
7514 * This macro will only compare value abdegh, it expects cfi to have already
7517 #define QTCHECK_MATRIX(m,a,b,d,e,g,h) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
7518 (m)[3] == (d << 16) && (m)[4] == (e << 16) && \
7519 (m)[6] == (g << 16) && (m)[7] == (h << 16))
7521 /* only handle the cases where the last column has standard values */
7522 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
7523 const gchar *rotation_tag = NULL;
7525 /* no rotation needed */
7526 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1, 0, 0)) {
7528 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0,
7529 stream->display_height, 0)) {
7530 rotation_tag = "rotate-90";
7531 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16,
7532 stream->display_width, stream->display_height)) {
7533 rotation_tag = "rotate-180";
7534 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0, 0,
7535 stream->display_width)) {
7536 rotation_tag = "rotate-270";
7538 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
7541 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
7543 if (rotation_tag != NULL) {
7544 if (*taglist == NULL)
7545 *taglist = gst_tag_list_new_empty ();
7546 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
7547 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
7550 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
7555 * With each track we associate a new QtDemuxStream that contains all the info
7557 * traks that do not decode to something (like strm traks) will not have a pad.
7560 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
7577 QtDemuxStream *stream = NULL;
7578 gboolean new_stream = FALSE;
7579 GstTagList *list = NULL;
7580 gchar *codec = NULL;
7581 const guint8 *stsd_data;
7582 guint16 lang_code; /* quicktime lang code or packed iso code */
7584 guint32 tkhd_flags = 0;
7585 guint8 tkhd_version = 0;
7587 guint value_size, stsd_len, len;
7590 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
7592 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
7593 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
7594 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
7597 /* pick between 64 or 32 bits */
7598 value_size = tkhd_version == 1 ? 8 : 4;
7599 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
7600 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
7603 if (!qtdemux->got_moov) {
7604 if (qtdemux_find_stream (qtdemux, track_id))
7605 goto existing_stream;
7606 stream = _create_stream ();
7607 stream->track_id = track_id;
7610 stream = qtdemux_find_stream (qtdemux, track_id);
7612 GST_WARNING_OBJECT (qtdemux, "Stream not found, going to ignore it");
7617 if ((tkhd_flags & 1) == 0)
7618 stream->disabled = TRUE;
7620 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
7621 tkhd_version, tkhd_flags, stream->track_id);
7623 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
7626 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
7627 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
7628 if (qtdemux->major_brand != FOURCC_mjp2 ||
7629 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
7633 len = QT_UINT32 ((guint8 *) mdhd->data);
7634 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
7635 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
7636 if (version == 0x01000000) {
7639 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
7640 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
7641 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
7645 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
7646 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
7647 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
7650 if (lang_code < 0x400) {
7651 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
7652 } else if (lang_code == 0x7fff) {
7653 stream->lang_id[0] = 0; /* unspecified */
7655 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
7656 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
7657 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
7658 stream->lang_id[3] = 0;
7661 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
7663 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
7665 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
7666 lang_code, stream->lang_id);
7668 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
7671 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
7672 /* chapters track reference */
7673 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
7675 gsize length = GST_READ_UINT32_BE (chap->data);
7676 if (qtdemux->chapters_track_id)
7677 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
7680 qtdemux->chapters_track_id =
7681 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
7686 /* fragmented files may have bogus duration in moov */
7687 if (!qtdemux->fragmented &&
7688 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
7689 guint64 tdur1, tdur2;
7691 /* don't overflow */
7692 tdur1 = stream->timescale * (guint64) qtdemux->duration;
7693 tdur2 = qtdemux->timescale * (guint64) stream->duration;
7696 * some of those trailers, nowadays, have prologue images that are
7697 * themselves vide tracks as well. I haven't really found a way to
7698 * identify those yet, except for just looking at their duration. */
7699 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
7700 GST_WARNING_OBJECT (qtdemux,
7701 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
7702 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
7703 "found, assuming preview image or something; skipping track",
7704 stream->duration, stream->timescale, qtdemux->duration,
7705 qtdemux->timescale);
7711 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
7714 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
7715 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
7717 len = QT_UINT32 ((guint8 *) hdlr->data);
7719 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
7720 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
7721 GST_FOURCC_ARGS (stream->subtype));
7723 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
7726 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
7730 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
7732 stsd_data = (const guint8 *) stsd->data;
7734 /* stsd should at least have one entry */
7735 stsd_len = QT_UINT32 (stsd_data);
7736 if (stsd_len < 24) {
7737 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
7738 if (stream->subtype == FOURCC_vivo) {
7746 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
7748 /* and that entry should fit within stsd */
7749 len = QT_UINT32 (stsd_data + 16);
7750 if (len > stsd_len + 16)
7753 stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
7754 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
7755 GST_FOURCC_ARGS (stream->fourcc));
7756 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
7758 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi) ||
7759 ((fourcc & 0x00FFFFFF) == GST_MAKE_FOURCC ('e', 'n', 'c', 0)))
7760 goto error_encrypted;
7762 if (stream->subtype == FOURCC_vide) {
7763 guint32 w = 0, h = 0;
7765 gint depth, palette_size, palette_count;
7767 guint32 *palette_data = NULL;
7769 stream->sampled = TRUE;
7771 /* version 1 uses some 64-bit ints */
7772 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
7775 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
7778 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
7779 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
7782 stream->display_width = w >> 16;
7783 stream->display_height = h >> 16;
7785 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix, &list);
7791 stream->width = QT_UINT16 (stsd_data + offset + 32);
7792 stream->height = QT_UINT16 (stsd_data + offset + 34);
7793 stream->fps_n = 0; /* this is filled in later */
7794 stream->fps_d = 0; /* this is filled in later */
7795 stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
7796 stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
7798 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
7799 stream->width, stream->height, stream->bits_per_sample,
7800 stream->color_table_id);
7802 depth = stream->bits_per_sample;
7804 /* more than 32 bits means grayscale */
7805 gray = (depth > 32);
7806 /* low 32 bits specify the depth */
7809 /* different number of palette entries is determined by depth. */
7811 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
7812 palette_count = (1 << depth);
7813 palette_size = palette_count * 4;
7815 if (stream->color_table_id) {
7816 switch (palette_count) {
7820 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
7823 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
7827 palette_data = g_memdup (ff_qt_grayscale_palette_16, palette_size);
7829 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
7833 palette_data = g_memdup (ff_qt_grayscale_palette_256, palette_size);
7835 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
7838 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
7839 (_("The video in this file might not play correctly.")),
7840 ("unsupported palette depth %d", depth));
7844 gint i, j, start, end;
7850 start = QT_UINT32 (stsd_data + offset + 86);
7851 palette_count = QT_UINT16 (stsd_data + offset + 90);
7852 end = QT_UINT16 (stsd_data + offset + 92);
7854 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
7855 start, end, palette_count);
7862 if (len < 94 + (end - start) * 8)
7865 /* palette is always the same size */
7866 palette_data = g_malloc0 (256 * 4);
7867 palette_size = 256 * 4;
7869 for (j = 0, i = start; i <= end; j++, i++) {
7872 a = QT_UINT16 (stsd_data + offset + 94 + (j * 8));
7873 r = QT_UINT16 (stsd_data + offset + 96 + (j * 8));
7874 g = QT_UINT16 (stsd_data + offset + 98 + (j * 8));
7875 b = QT_UINT16 (stsd_data + offset + 100 + (j * 8));
7877 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
7878 (g & 0xff00) | (b >> 8);
7883 qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
7884 if (G_UNLIKELY (!stream->caps)) {
7885 g_free (palette_data);
7886 goto unknown_stream;
7891 list = gst_tag_list_new_empty ();
7892 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7893 GST_TAG_VIDEO_CODEC, codec, NULL);
7902 if (stream->rgb8_palette)
7903 gst_memory_unref (stream->rgb8_palette);
7904 stream->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
7905 palette_data, palette_size, 0, palette_size, palette_data, g_free);
7907 s = gst_caps_get_structure (stream->caps, 0);
7909 /* non-raw video has a palette_data property. raw video has the palette as
7910 * an extra plane that we append to the output buffers before we push
7912 if (!gst_structure_has_name (s, "video/x-raw")) {
7915 palette = gst_buffer_new ();
7916 gst_buffer_append_memory (palette, stream->rgb8_palette);
7917 stream->rgb8_palette = NULL;
7919 gst_caps_set_simple (stream->caps, "palette_data",
7920 GST_TYPE_BUFFER, palette, NULL);
7921 gst_buffer_unref (palette);
7923 } else if (palette_count != 0) {
7924 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
7925 (NULL), ("Unsupported palette depth %d", depth));
7928 GST_LOG_OBJECT (qtdemux, "frame count: %u",
7929 QT_UINT16 (stsd_data + offset + 48));
7933 /* pick 'the' stsd child */
7934 mp4v = qtdemux_tree_get_child_by_type (stsd, fourcc);
7936 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
7937 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
7941 const guint8 *pasp_data = (const guint8 *) pasp->data;
7943 stream->par_w = QT_UINT32 (pasp_data + 8);
7944 stream->par_h = QT_UINT32 (pasp_data + 12);
7951 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
7958 gint len = QT_UINT32 (stsd_data) - 0x66;
7959 const guint8 *avc_data = stsd_data + 0x66;
7962 while (len >= 0x8) {
7965 if (QT_UINT32 (avc_data) <= len)
7966 size = QT_UINT32 (avc_data) - 0x8;
7971 /* No real data, so break out */
7974 switch (QT_FOURCC (avc_data + 0x4)) {
7977 /* parse, if found */
7980 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
7982 /* First 4 bytes are the length of the atom, the next 4 bytes
7983 * are the fourcc, the next 1 byte is the version, and the
7984 * subsequent bytes are profile_tier_level structure like data. */
7985 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
7986 avc_data + 8 + 1, size - 1);
7987 buf = gst_buffer_new_and_alloc (size);
7988 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
7989 gst_caps_set_simple (stream->caps,
7990 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7991 gst_buffer_unref (buf);
7999 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
8001 /* First 4 bytes are the length of the atom, the next 4 bytes
8002 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
8003 * next 1 byte is the version, and the
8004 * subsequent bytes are sequence parameter set like data. */
8006 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
8008 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
8009 avc_data + 8 + 40 + 1, size - 1);
8011 buf = gst_buffer_new_and_alloc (size);
8012 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
8013 gst_caps_set_simple (stream->caps,
8014 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8015 gst_buffer_unref (buf);
8021 guint avg_bitrate, max_bitrate;
8023 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
8027 max_bitrate = QT_UINT32 (avc_data + 0xc);
8028 avg_bitrate = QT_UINT32 (avc_data + 0x10);
8030 if (!max_bitrate && !avg_bitrate)
8033 /* Some muxers seem to swap the average and maximum bitrates
8034 * (I'm looking at you, YouTube), so we swap for sanity. */
8035 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
8036 guint temp = avg_bitrate;
8038 avg_bitrate = max_bitrate;
8043 list = gst_tag_list_new_empty ();
8045 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
8046 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
8047 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
8049 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
8050 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
8051 GST_TAG_BITRATE, avg_bitrate, NULL);
8062 avc_data += size + 8;
8071 gint len = QT_UINT32 (stsd_data) - 0x66;
8072 const guint8 *hevc_data = stsd_data + 0x66;
8075 while (len >= 0x8) {
8078 if (QT_UINT32 (hevc_data) <= len)
8079 size = QT_UINT32 (hevc_data) - 0x8;
8084 /* No real data, so break out */
8087 switch (QT_FOURCC (hevc_data + 0x4)) {
8090 /* parse, if found */
8093 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
8095 /* First 4 bytes are the length of the atom, the next 4 bytes
8096 * are the fourcc, the next 1 byte is the version, and the
8097 * subsequent bytes are sequence parameter set like data. */
8098 gst_codec_utils_h265_caps_set_level_tier_and_profile
8099 (stream->caps, hevc_data + 8 + 1, size - 1);
8101 buf = gst_buffer_new_and_alloc (size);
8102 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
8103 gst_caps_set_simple (stream->caps,
8104 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8105 gst_buffer_unref (buf);
8112 hevc_data += size + 8;
8123 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
8124 GST_FOURCC_ARGS (fourcc));
8126 /* codec data might be in glbl extension atom */
8128 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
8134 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
8136 len = QT_UINT32 (data);
8139 buf = gst_buffer_new_and_alloc (len);
8140 gst_buffer_fill (buf, 0, data + 8, len);
8141 gst_caps_set_simple (stream->caps,
8142 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8143 gst_buffer_unref (buf);
8150 /* see annex I of the jpeg2000 spec */
8151 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
8153 const gchar *colorspace = NULL;
8155 guint32 ncomp_map = 0;
8156 gint32 *comp_map = NULL;
8157 guint32 nchan_def = 0;
8158 gint32 *chan_def = NULL;
8160 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
8161 /* some required atoms */
8162 mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
8165 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
8169 /* number of components; redundant with info in codestream, but useful
8171 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
8172 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
8174 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
8176 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
8179 GST_DEBUG_OBJECT (qtdemux, "found colr");
8180 /* extract colour space info */
8181 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
8182 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
8184 colorspace = "sRGB";
8187 colorspace = "GRAY";
8190 colorspace = "sYUV";
8198 /* colr is required, and only values 16, 17, and 18 are specified,
8199 so error if we have no colorspace */
8202 /* extract component mapping */
8203 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
8205 guint32 cmap_len = 0;
8207 cmap_len = QT_UINT32 (cmap->data);
8208 if (cmap_len >= 8) {
8209 /* normal box, subtract off header */
8211 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
8212 if (cmap_len % 4 == 0) {
8213 ncomp_map = (cmap_len / 4);
8214 comp_map = g_new0 (gint32, ncomp_map);
8215 for (i = 0; i < ncomp_map; i++) {
8218 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
8219 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
8220 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
8221 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
8226 /* extract channel definitions */
8227 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
8229 guint32 cdef_len = 0;
8231 cdef_len = QT_UINT32 (cdef->data);
8232 if (cdef_len >= 10) {
8233 /* normal box, subtract off header and len */
8235 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
8236 if (cdef_len % 6 == 0) {
8237 nchan_def = (cdef_len / 6);
8238 chan_def = g_new0 (gint32, nchan_def);
8239 for (i = 0; i < nchan_def; i++)
8241 for (i = 0; i < nchan_def; i++) {
8242 guint16 cn, typ, asoc;
8243 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
8244 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
8245 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
8246 if (cn < nchan_def) {
8249 chan_def[cn] = asoc;
8252 chan_def[cn] = 0; /* alpha */
8255 chan_def[cn] = -typ;
8263 gst_caps_set_simple (stream->caps,
8264 "num-components", G_TYPE_INT, ncomp, NULL);
8265 gst_caps_set_simple (stream->caps,
8266 "colorspace", G_TYPE_STRING, colorspace, NULL);
8269 GValue arr = { 0, };
8270 GValue elt = { 0, };
8272 g_value_init (&arr, GST_TYPE_ARRAY);
8273 g_value_init (&elt, G_TYPE_INT);
8274 for (i = 0; i < ncomp_map; i++) {
8275 g_value_set_int (&elt, comp_map[i]);
8276 gst_value_array_append_value (&arr, &elt);
8278 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
8279 "component-map", &arr);
8280 g_value_unset (&elt);
8281 g_value_unset (&arr);
8286 GValue arr = { 0, };
8287 GValue elt = { 0, };
8289 g_value_init (&arr, GST_TYPE_ARRAY);
8290 g_value_init (&elt, G_TYPE_INT);
8291 for (i = 0; i < nchan_def; i++) {
8292 g_value_set_int (&elt, chan_def[i]);
8293 gst_value_array_append_value (&arr, &elt);
8295 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
8296 "channel-definitions", &arr);
8297 g_value_unset (&elt);
8298 g_value_unset (&arr);
8302 /* some optional atoms */
8303 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
8304 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
8306 /* indicate possible fields in caps */
8308 data = (guint8 *) field->data + 8;
8310 gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
8311 (gint) * data, NULL);
8313 /* add codec_data if provided */
8318 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
8319 data = prefix->data;
8320 len = QT_UINT32 (data);
8323 buf = gst_buffer_new_and_alloc (len);
8324 gst_buffer_fill (buf, 0, data + 8, len);
8325 gst_caps_set_simple (stream->caps,
8326 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8327 gst_buffer_unref (buf);
8336 GstBuffer *seqh = NULL;
8337 guint8 *gamma_data = NULL;
8338 gint len = QT_UINT32 (stsd_data);
8340 qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
8342 gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
8343 QT_FP32 (gamma_data), NULL);
8346 /* sorry for the bad name, but we don't know what this is, other
8347 * than its own fourcc */
8348 gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
8352 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
8353 buf = gst_buffer_new_and_alloc (len);
8354 gst_buffer_fill (buf, 0, stsd_data, len);
8355 gst_caps_set_simple (stream->caps,
8356 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8357 gst_buffer_unref (buf);
8363 gst_caps_set_simple (stream->caps,
8364 "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
8371 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
8372 xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
8376 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
8380 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
8381 /* collect the headers and store them in a stream list so that we can
8382 * send them out first */
8383 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
8393 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
8394 ovc1 = qtdemux_tree_get_child_by_type (stsd, FOURCC_ovc1);
8397 ovc1_data = ovc1->data;
8398 ovc1_len = QT_UINT32 (ovc1_data);
8399 if (ovc1_len <= 198) {
8400 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
8403 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
8404 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
8405 gst_caps_set_simple (stream->caps,
8406 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8407 gst_buffer_unref (buf);
8410 case GST_MAKE_FOURCC ('v', 'c', '-', '1'):
8412 gint len = QT_UINT32 (stsd_data) - 0x66;
8413 const guint8 *vc1_data = stsd_data + 0x66;
8419 if (QT_UINT32 (vc1_data) <= len)
8420 size = QT_UINT32 (vc1_data) - 8;
8425 /* No real data, so break out */
8428 switch (QT_FOURCC (vc1_data + 0x4)) {
8429 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
8433 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
8434 buf = gst_buffer_new_and_alloc (size);
8435 gst_buffer_fill (buf, 0, vc1_data + 8, size);
8436 gst_caps_set_simple (stream->caps,
8437 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8438 gst_buffer_unref (buf);
8445 vc1_data += size + 8;
8454 GST_INFO_OBJECT (qtdemux,
8455 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
8456 GST_FOURCC_ARGS (fourcc), stream->caps);
8458 } else if (stream->subtype == FOURCC_soun) {
8459 int version, samplesize;
8460 guint16 compression_id;
8461 gboolean amrwb = FALSE;
8464 /* sample description entry (16) + sound sample description v0 (20) */
8468 version = QT_UINT32 (stsd_data + offset);
8469 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
8470 samplesize = QT_UINT16 (stsd_data + offset + 10);
8471 compression_id = QT_UINT16 (stsd_data + offset + 12);
8472 stream->rate = QT_FP32 (stsd_data + offset + 16);
8474 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
8475 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
8476 QT_UINT32 (stsd_data + offset + 4));
8477 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
8478 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
8479 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
8480 GST_LOG_OBJECT (qtdemux, "packet size: %d",
8481 QT_UINT16 (stsd_data + offset + 14));
8482 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
8484 if (compression_id == 0xfffe)
8485 stream->sampled = TRUE;
8487 /* first assume uncompressed audio */
8488 stream->bytes_per_sample = samplesize / 8;
8489 stream->samples_per_frame = stream->n_channels;
8490 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
8491 stream->samples_per_packet = stream->samples_per_frame;
8492 stream->bytes_per_packet = stream->bytes_per_sample;
8496 /* Yes, these have to be hard-coded */
8499 stream->samples_per_packet = 6;
8500 stream->bytes_per_packet = 1;
8501 stream->bytes_per_frame = 1 * stream->n_channels;
8502 stream->bytes_per_sample = 1;
8503 stream->samples_per_frame = 6 * stream->n_channels;
8508 stream->samples_per_packet = 3;
8509 stream->bytes_per_packet = 1;
8510 stream->bytes_per_frame = 1 * stream->n_channels;
8511 stream->bytes_per_sample = 1;
8512 stream->samples_per_frame = 3 * stream->n_channels;
8517 stream->samples_per_packet = 64;
8518 stream->bytes_per_packet = 34;
8519 stream->bytes_per_frame = 34 * stream->n_channels;
8520 stream->bytes_per_sample = 2;
8521 stream->samples_per_frame = 64 * stream->n_channels;
8527 stream->samples_per_packet = 1;
8528 stream->bytes_per_packet = 1;
8529 stream->bytes_per_frame = 1 * stream->n_channels;
8530 stream->bytes_per_sample = 1;
8531 stream->samples_per_frame = 1 * stream->n_channels;
8536 stream->samples_per_packet = 160;
8537 stream->bytes_per_packet = 33;
8538 stream->bytes_per_frame = 33 * stream->n_channels;
8539 stream->bytes_per_sample = 2;
8540 stream->samples_per_frame = 160 * stream->n_channels;
8547 if (version == 0x00010000) {
8548 /* sample description entry (16) + sound sample description v1 (20+16) */
8559 /* only parse extra decoding config for non-pcm audio */
8560 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
8561 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
8562 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
8563 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
8565 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
8566 stream->samples_per_packet);
8567 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
8568 stream->bytes_per_packet);
8569 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
8570 stream->bytes_per_frame);
8571 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
8572 stream->bytes_per_sample);
8574 if (!stream->sampled && stream->bytes_per_packet) {
8575 stream->samples_per_frame = (stream->bytes_per_frame /
8576 stream->bytes_per_packet) * stream->samples_per_packet;
8577 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
8578 stream->samples_per_frame);
8583 } else if (version == 0x00020000) {
8590 /* sample description entry (16) + sound sample description v2 (56) */
8594 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
8595 stream->rate = qtfp.fp;
8596 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
8598 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
8599 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
8600 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
8601 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
8602 QT_UINT32 (stsd_data + offset + 20));
8603 GST_LOG_OBJECT (qtdemux, "format flags: %X",
8604 QT_UINT32 (stsd_data + offset + 24));
8605 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
8606 QT_UINT32 (stsd_data + offset + 28));
8607 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
8608 QT_UINT32 (stsd_data + offset + 32));
8609 } else if (version != 0x00000) {
8610 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x", version);
8613 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc,
8614 stsd_data + 32, len - 16, &codec);
8622 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
8624 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
8626 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
8628 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
8631 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
8632 gst_caps_set_simple (stream->caps,
8633 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE", NULL);
8640 const guint8 *owma_data;
8641 const gchar *codec_name = NULL;
8645 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
8646 /* FIXME this should also be gst_riff_strf_auds,
8647 * but the latter one is actually missing bits-per-sample :( */
8652 gint32 nSamplesPerSec;
8653 gint32 nAvgBytesPerSec;
8655 gint16 wBitsPerSample;
8660 GST_DEBUG_OBJECT (qtdemux, "parse owma");
8661 owma = qtdemux_tree_get_child_by_type (stsd, FOURCC_owma);
8664 owma_data = owma->data;
8665 owma_len = QT_UINT32 (owma_data);
8666 if (owma_len <= 54) {
8667 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
8670 wfex = (WAVEFORMATEX *) (owma_data + 36);
8671 buf = gst_buffer_new_and_alloc (owma_len - 54);
8672 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
8673 if (wfex->wFormatTag == 0x0161) {
8674 codec_name = "Windows Media Audio";
8676 } else if (wfex->wFormatTag == 0x0162) {
8677 codec_name = "Windows Media Audio 9 Pro";
8679 } else if (wfex->wFormatTag == 0x0163) {
8680 codec_name = "Windows Media Audio 9 Lossless";
8681 /* is that correct? gstffmpegcodecmap.c is missing it, but
8682 * fluendo codec seems to support it */
8686 gst_caps_set_simple (stream->caps,
8687 "codec_data", GST_TYPE_BUFFER, buf,
8688 "wmaversion", G_TYPE_INT, version,
8689 "block_align", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->nBlockAlign),
8690 "bitrate", G_TYPE_INT, GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec),
8691 "width", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
8692 "depth", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
8694 gst_buffer_unref (buf);
8698 codec = g_strdup (codec_name);
8702 case GST_MAKE_FOURCC ('w', 'm', 'a', ' '):
8704 gint len = QT_UINT32 (stsd_data) - offset;
8705 const guint8 *wfex_data = stsd_data + offset;
8706 const gchar *codec_name = NULL;
8708 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
8709 /* FIXME this should also be gst_riff_strf_auds,
8710 * but the latter one is actually missing bits-per-sample :( */
8715 gint32 nSamplesPerSec;
8716 gint32 nAvgBytesPerSec;
8718 gint16 wBitsPerSample;
8723 /* FIXME: unify with similar wavformatex parsing code above */
8724 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
8730 if (QT_UINT32 (wfex_data) <= len)
8731 size = QT_UINT32 (wfex_data) - 8;
8736 /* No real data, so break out */
8739 switch (QT_FOURCC (wfex_data + 4)) {
8740 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
8742 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
8747 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
8748 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
8749 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
8750 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
8751 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
8752 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
8753 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
8755 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
8756 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
8757 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
8758 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
8759 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
8760 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
8762 if (wfex.wFormatTag == 0x0161) {
8763 codec_name = "Windows Media Audio";
8765 } else if (wfex.wFormatTag == 0x0162) {
8766 codec_name = "Windows Media Audio 9 Pro";
8768 } else if (wfex.wFormatTag == 0x0163) {
8769 codec_name = "Windows Media Audio 9 Lossless";
8770 /* is that correct? gstffmpegcodecmap.c is missing it, but
8771 * fluendo codec seems to support it */
8775 gst_caps_set_simple (stream->caps,
8776 "wmaversion", G_TYPE_INT, version,
8777 "block_align", G_TYPE_INT, wfex.nBlockAlign,
8778 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
8779 "width", G_TYPE_INT, wfex.wBitsPerSample,
8780 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
8782 if (size > wfex.cbSize) {
8785 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
8786 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
8787 size - wfex.cbSize);
8788 gst_caps_set_simple (stream->caps,
8789 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8790 gst_buffer_unref (buf);
8792 GST_WARNING_OBJECT (qtdemux, "no codec data");
8797 codec = g_strdup (codec_name);
8805 wfex_data += size + 8;
8818 list = gst_tag_list_new_empty ();
8819 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
8820 GST_TAG_AUDIO_CODEC, codec, NULL);
8824 /* some bitrate info may have ended up in caps */
8825 s = gst_caps_get_structure (stream->caps, 0);
8826 gst_structure_get_int (s, "bitrate", &bitrate);
8828 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
8832 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
8836 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
8838 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
8840 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
8844 /* If the fourcc's bottom 16 bits gives 'sm', then the top
8845 16 bits is a byte-swapped wave-style codec identifier,
8846 and we can find a WAVE header internally to a 'wave' atom here.
8847 This can more clearly be thought of as 'ms' as the top 16 bits, and a
8848 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
8851 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
8852 if (len < offset + 20) {
8853 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
8855 guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
8856 const guint8 *data = stsd_data + offset + 16;
8858 GNode *waveheadernode;
8860 wavenode = g_node_new ((guint8 *) data);
8861 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
8862 const guint8 *waveheader;
8865 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
8866 if (waveheadernode) {
8867 waveheader = (const guint8 *) waveheadernode->data;
8868 headerlen = QT_UINT32 (waveheader);
8870 if (headerlen > 8) {
8871 gst_riff_strf_auds *header = NULL;
8872 GstBuffer *headerbuf;
8878 headerbuf = gst_buffer_new_and_alloc (headerlen);
8879 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
8881 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
8882 headerbuf, &header, &extra)) {
8883 gst_caps_unref (stream->caps);
8884 /* FIXME: Need to do something with the channel reorder map */
8885 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
8886 header, extra, NULL, NULL, NULL);
8889 gst_buffer_unref (extra);
8894 GST_DEBUG ("Didn't find waveheadernode for this codec");
8896 g_node_destroy (wavenode);
8899 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
8903 /* FIXME: what is in the chunk? */
8906 gint len = QT_UINT32 (stsd_data);
8908 /* seems to be always = 116 = 0x74 */
8914 gint len = QT_UINT32 (stsd_data);
8917 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
8919 gst_buffer_fill (buf, 0, stsd_data + 0x4C, len - 0x4C);
8920 gst_caps_set_simple (stream->caps,
8921 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8922 gst_buffer_unref (buf);
8924 gst_caps_set_simple (stream->caps,
8925 "samplesize", G_TYPE_INT, samplesize, NULL);
8930 GNode *alac, *wave = NULL;
8932 /* apparently, m4a has this atom appended directly in the stsd entry,
8933 * while mov has it in a wave atom */
8934 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
8936 /* alac now refers to stsd entry atom */
8937 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
8939 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
8941 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
8944 const guint8 *alac_data = alac->data;
8945 gint len = QT_UINT32 (alac->data);
8949 GST_DEBUG_OBJECT (qtdemux,
8950 "discarding alac atom with unexpected len %d", len);
8952 /* codec-data contains alac atom size and prefix,
8953 * ffmpeg likes it that way, not quite gst-ish though ...*/
8954 buf = gst_buffer_new_and_alloc (len);
8955 gst_buffer_fill (buf, 0, alac->data, len);
8956 gst_caps_set_simple (stream->caps,
8957 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8958 gst_buffer_unref (buf);
8960 stream->bytes_per_frame = QT_UINT32 (alac_data + 12);
8961 stream->n_channels = QT_UINT8 (alac_data + 21);
8962 stream->rate = QT_UINT32 (alac_data + 32);
8965 gst_caps_set_simple (stream->caps,
8966 "samplesize", G_TYPE_INT, samplesize, NULL);
8974 gint len = QT_UINT32 (stsd_data);
8977 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
8980 gst_buffer_fill (buf, 0, stsd_data + 0x34, len - 0x34);
8982 /* If we have enough data, let's try to get the 'damr' atom. See
8983 * the 3GPP container spec (26.244) for more details. */
8984 if ((len - 0x34) > 8 &&
8985 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
8987 list = gst_tag_list_new_empty ();
8988 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
8989 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
8992 gst_caps_set_simple (stream->caps,
8993 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8994 gst_buffer_unref (buf);
9000 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
9001 gint len = QT_UINT32 (stsd_data);
9004 guint16 sound_version = QT_UINT16 (stsd_data + 32);
9006 if (sound_version == 1) {
9007 guint16 channels = QT_UINT16 (stsd_data + 40);
9008 guint32 time_scale = QT_UINT32 (stsd_data + 46);
9009 guint8 codec_data[2];
9011 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
9013 gint sample_rate_index =
9014 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
9016 /* build AAC codec data */
9017 codec_data[0] = profile << 3;
9018 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
9019 codec_data[1] = (sample_rate_index & 0x01) << 7;
9020 codec_data[1] |= (channels & 0xF) << 3;
9022 buf = gst_buffer_new_and_alloc (2);
9023 gst_buffer_fill (buf, 0, codec_data, 2);
9024 gst_caps_set_simple (stream->caps,
9025 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9026 gst_buffer_unref (buf);
9032 GST_INFO_OBJECT (qtdemux,
9033 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
9037 GST_INFO_OBJECT (qtdemux,
9038 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
9039 GST_FOURCC_ARGS (fourcc), stream->caps);
9041 } else if (stream->subtype == FOURCC_strm) {
9042 if (fourcc == FOURCC_rtsp) {
9043 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
9045 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
9046 GST_FOURCC_ARGS (fourcc));
9047 goto unknown_stream;
9049 stream->sampled = TRUE;
9050 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
9051 || stream->subtype == FOURCC_sbtl) {
9053 stream->sampled = TRUE;
9054 stream->sparse = TRUE;
9057 qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
9059 list = gst_tag_list_new_empty ();
9060 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
9061 GST_TAG_SUBTITLE_CODEC, codec, NULL);
9066 /* hunt for sort-of codec data */
9073 /* look for palette in a stsd->mp4s->esds sub-atom */
9074 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
9076 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
9079 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
9083 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
9087 GST_INFO_OBJECT (qtdemux,
9088 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
9091 GST_INFO_OBJECT (qtdemux,
9092 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
9093 GST_FOURCC_ARGS (fourcc), stream->caps);
9095 /* everything in 1 sample */
9096 stream->sampled = TRUE;
9099 qtdemux_generic_caps (qtdemux, stream, fourcc, stsd_data, &codec);
9101 if (stream->caps == NULL)
9102 goto unknown_stream;
9105 list = gst_tag_list_new_empty ();
9106 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
9107 GST_TAG_SUBTITLE_CODEC, codec, NULL);
9113 /* promote to sampled format */
9114 if (stream->fourcc == FOURCC_samr) {
9115 /* force mono 8000 Hz for AMR */
9116 stream->sampled = TRUE;
9117 stream->n_channels = 1;
9118 stream->rate = 8000;
9119 } else if (stream->fourcc == FOURCC_sawb) {
9120 /* force mono 16000 Hz for AMR-WB */
9121 stream->sampled = TRUE;
9122 stream->n_channels = 1;
9123 stream->rate = 16000;
9124 } else if (stream->fourcc == FOURCC_mp4a) {
9125 stream->sampled = TRUE;
9128 /* collect sample information */
9129 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
9130 goto samples_failed;
9132 if (qtdemux->fragmented) {
9136 /* need all moov samples as basis; probably not many if any at all */
9137 /* prevent moof parsing taking of at this time */
9138 offset = qtdemux->moof_offset;
9139 qtdemux->moof_offset = 0;
9140 if (stream->n_samples &&
9141 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
9142 qtdemux->moof_offset = offset;
9143 goto samples_failed;
9145 qtdemux->moof_offset = 0;
9146 /* movie duration more reliable in this case (e.g. mehd) */
9147 if (qtdemux->segment.duration &&
9148 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
9150 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
9151 /* need defaults for fragments */
9152 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
9155 /* configure segments */
9156 if (!qtdemux_parse_segments (qtdemux, stream, trak))
9157 goto segments_failed;
9159 /* add some language tag, if useful */
9160 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
9161 strcmp (stream->lang_id, "und")) {
9162 const gchar *lang_code;
9165 list = gst_tag_list_new_empty ();
9167 /* convert ISO 639-2 code to ISO 639-1 */
9168 lang_code = gst_tag_get_language_code (stream->lang_id);
9169 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
9170 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
9173 /* now we are ready to add the stream */
9174 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
9175 goto too_many_streams;
9177 if (!qtdemux->got_moov) {
9178 stream->pending_tags = list;
9179 qtdemux->streams[qtdemux->n_streams] = stream;
9180 qtdemux->n_streams++;
9181 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
9189 GST_INFO_OBJECT (qtdemux, "skip disabled track");
9196 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9197 (_("This file is corrupt and cannot be played.")), (NULL));
9204 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
9212 /* we posted an error already */
9213 /* free stbl sub-atoms */
9214 gst_qtdemux_stbl_free (stream);
9221 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
9229 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
9230 GST_FOURCC_ARGS (stream->subtype));
9237 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
9238 (_("This file contains too many streams. Only playing first %d"),
9239 GST_QTDEMUX_MAX_STREAMS), (NULL));
9244 /* If we can estimate the overall bitrate, and don't have information about the
9245 * stream bitrate for exactly one stream, this guesses the stream bitrate as
9246 * the overall bitrate minus the sum of the bitrates of all other streams. This
9247 * should be useful for the common case where we have one audio and one video
9248 * stream and can estimate the bitrate of one, but not the other. */
9250 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
9252 QtDemuxStream *stream = NULL;
9253 gint64 size, sys_bitrate, sum_bitrate = 0;
9254 GstClockTime duration;
9258 if (qtdemux->fragmented)
9261 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
9263 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
9265 GST_DEBUG_OBJECT (qtdemux,
9266 "Size in bytes of the stream not known - bailing");
9270 /* Subtract the header size */
9271 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
9272 size, qtdemux->header_size);
9274 if (size < qtdemux->header_size)
9277 size = size - qtdemux->header_size;
9279 if (!gst_qtdemux_get_duration (qtdemux, &duration) ||
9280 duration == GST_CLOCK_TIME_NONE) {
9281 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
9285 for (i = 0; i < qtdemux->n_streams; i++) {
9286 switch (qtdemux->streams[i]->subtype) {
9289 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
9290 qtdemux->streams[i]->caps);
9291 /* retrieve bitrate, prefer avg then max */
9293 if (qtdemux->streams[i]->pending_tags) {
9294 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
9295 GST_TAG_MAXIMUM_BITRATE, &bitrate);
9296 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
9297 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
9298 GST_TAG_NOMINAL_BITRATE, &bitrate);
9299 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
9300 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
9301 GST_TAG_BITRATE, &bitrate);
9302 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
9305 sum_bitrate += bitrate;
9308 GST_DEBUG_OBJECT (qtdemux,
9309 ">1 stream with unknown bitrate - bailing");
9312 stream = qtdemux->streams[i];
9316 /* For other subtypes, we assume no significant impact on bitrate */
9322 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
9326 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
9328 if (sys_bitrate < sum_bitrate) {
9329 /* This can happen, since sum_bitrate might be derived from maximum
9330 * bitrates and not average bitrates */
9331 GST_DEBUG_OBJECT (qtdemux,
9332 "System bitrate less than sum bitrate - bailing");
9336 bitrate = sys_bitrate - sum_bitrate;
9337 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
9338 ", Stream bitrate = %u", sys_bitrate, bitrate);
9340 if (!stream->pending_tags)
9341 stream->pending_tags = gst_tag_list_new_empty ();
9343 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9344 GST_TAG_BITRATE, bitrate, NULL);
9347 static GstFlowReturn
9348 qtdemux_prepare_streams (GstQTDemux * qtdemux)
9351 GstFlowReturn ret = GST_FLOW_OK;
9353 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
9355 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
9356 QtDemuxStream *stream = qtdemux->streams[i];
9357 guint32 sample_num = 0;
9359 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
9360 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
9362 if (qtdemux->fragmented) {
9363 /* need all moov samples first */
9364 GST_OBJECT_LOCK (qtdemux);
9365 while (stream->n_samples == 0)
9366 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
9368 GST_OBJECT_UNLOCK (qtdemux);
9370 /* discard any stray moof */
9371 qtdemux->moof_offset = 0;
9374 /* prepare braking */
9375 if (ret != GST_FLOW_ERROR)
9378 /* in pull mode, we should have parsed some sample info by now;
9379 * and quite some code will not handle no samples.
9380 * in push mode, we'll just have to deal with it */
9381 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
9382 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
9383 gst_qtdemux_remove_stream (qtdemux, i);
9388 /* parse the initial sample for use in setting the frame rate cap */
9389 while (sample_num == 0 && sample_num < stream->n_samples) {
9390 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
9394 if (stream->n_samples > 0 && stream->stbl_index > 0) {
9395 stream->first_duration = stream->samples[0].duration;
9396 GST_LOG_OBJECT (qtdemux, "stream %d first duration %u",
9397 stream->track_id, stream->first_duration);
9404 static GstFlowReturn
9405 qtdemux_expose_streams (GstQTDemux * qtdemux)
9408 GstFlowReturn ret = GST_FLOW_OK;
9409 GSList *oldpads = NULL;
9412 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
9414 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
9415 QtDemuxStream *stream = qtdemux->streams[i];
9416 GstPad *oldpad = stream->pad;
9419 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
9420 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
9422 if ((stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl) &&
9423 stream->track_id == qtdemux->chapters_track_id) {
9424 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
9425 so that it doesn't look like a subtitle track */
9426 gst_qtdemux_remove_stream (qtdemux, i);
9431 /* now we have all info and can expose */
9432 list = stream->pending_tags;
9433 stream->pending_tags = NULL;
9435 oldpads = g_slist_prepend (oldpads, oldpad);
9436 gst_qtdemux_add_stream (qtdemux, stream, list);
9439 gst_qtdemux_guess_bitrate (qtdemux);
9441 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
9443 for (iter = oldpads; iter; iter = g_slist_next (iter)) {
9444 GstPad *oldpad = iter->data;
9446 gst_pad_push_event (oldpad, gst_event_new_eos ());
9447 gst_pad_set_active (oldpad, FALSE);
9448 gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
9449 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, oldpad);
9450 gst_object_unref (oldpad);
9453 /* check if we should post a redirect in case there is a single trak
9454 * and it is a redirecting trak */
9455 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
9458 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
9459 "an external content");
9460 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
9461 gst_structure_new ("redirect",
9462 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
9464 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
9465 qtdemux->posted_redirect = TRUE;
9468 for (i = 0; i < qtdemux->n_streams; i++) {
9469 QtDemuxStream *stream = qtdemux->streams[i];
9471 qtdemux_do_allocation (qtdemux, stream);
9474 qtdemux->exposed = TRUE;
9478 /* check if major or compatible brand is 3GP */
9479 static inline gboolean
9480 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
9483 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
9484 GST_MAKE_FOURCC ('3', 'g', 0, 0));
9485 } else if (qtdemux->comp_brands != NULL) {
9489 gboolean res = FALSE;
9491 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
9495 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
9496 GST_MAKE_FOURCC ('3', 'g', 0, 0));
9500 gst_buffer_unmap (qtdemux->comp_brands, &map);
9507 /* check if tag is a spec'ed 3GP tag keyword storing a string */
9508 static inline gboolean
9509 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
9511 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
9512 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
9513 || fourcc == FOURCC_albm;
9517 qtdemux_tag_add_location (GstQTDemux * qtdemux, const char *tag,
9518 const char *dummy, GNode * node)
9520 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
9524 gdouble longitude, latitude, altitude;
9527 len = QT_UINT32 (node->data);
9534 /* TODO: language code skipped */
9536 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
9539 /* do not alarm in trivial case, but bail out otherwise */
9540 if (*(data + offset) != 0) {
9541 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
9545 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9546 GST_TAG_GEO_LOCATION_NAME, name, NULL);
9547 offset += strlen (name);
9551 if (len < offset + 2 + 4 + 4 + 4)
9554 /* +1 +1 = skip null-terminator and location role byte */
9556 /* table in spec says unsigned, semantics say negative has meaning ... */
9557 longitude = QT_SFP32 (data + offset);
9560 latitude = QT_SFP32 (data + offset);
9563 altitude = QT_SFP32 (data + offset);
9565 /* one invalid means all are invalid */
9566 if (longitude >= -180.0 && longitude <= 180.0 &&
9567 latitude >= -90.0 && latitude <= 90.0) {
9568 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9569 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
9570 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
9571 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
9574 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
9581 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
9588 qtdemux_tag_add_year (GstQTDemux * qtdemux, const char *tag, const char *dummy,
9595 len = QT_UINT32 (node->data);
9599 y = QT_UINT16 ((guint8 *) node->data + 12);
9601 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
9604 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
9606 date = g_date_new_dmy (1, 1, y);
9607 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, date, NULL);
9612 qtdemux_tag_add_classification (GstQTDemux * qtdemux, const char *tag,
9613 const char *dummy, GNode * node)
9616 char *tag_str = NULL;
9621 len = QT_UINT32 (node->data);
9626 entity = (guint8 *) node->data + offset;
9627 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
9628 GST_DEBUG_OBJECT (qtdemux,
9629 "classification info: %c%c%c%c invalid classification entity",
9630 entity[0], entity[1], entity[2], entity[3]);
9635 table = QT_UINT16 ((guint8 *) node->data + offset);
9637 /* Language code skipped */
9641 /* Tag format: "XXXX://Y[YYYY]/classification info string"
9642 * XXXX: classification entity, fixed length 4 chars.
9643 * Y[YYYY]: classification table, max 5 chars.
9645 tag_str = g_strdup_printf ("----://%u/%s",
9646 table, (char *) node->data + offset);
9648 /* memcpy To be sure we're preserving byte order */
9649 memcpy (tag_str, entity, 4);
9650 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
9652 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_APPEND, tag,
9662 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
9668 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, const char *tag,
9669 const char *dummy, GNode * node)
9671 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
9677 gboolean ret = TRUE;
9678 const gchar *charset = NULL;
9680 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9682 len = QT_UINT32 (data->data);
9683 type = QT_UINT32 ((guint8 *) data->data + 8);
9684 if (type == 0x00000001 && len > 16) {
9685 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
9688 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
9689 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s,
9693 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
9697 len = QT_UINT32 (node->data);
9698 type = QT_UINT32 ((guint8 *) node->data + 4);
9699 if ((type >> 24) == 0xa9) {
9703 /* Type starts with the (C) symbol, so the next data is a list
9704 * of (string size(16), language code(16), string) */
9706 str_len = QT_UINT16 ((guint8 *) node->data + 8);
9707 lang_code = QT_UINT16 ((guint8 *) node->data + 10);
9709 /* the string + fourcc + size + 2 16bit fields,
9710 * means that there are more tags in this atom */
9711 if (len > str_len + 8 + 4) {
9712 /* TODO how to represent the same tag in different languages? */
9713 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
9714 "text alternatives, reading only first one");
9718 len = str_len + 8 + 4; /* remove trailing strings that we don't use */
9719 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
9721 if (lang_code < 0x800) { /* MAC encoded string */
9724 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
9725 QT_FOURCC ((guint8 *) node->data + 4))) {
9726 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
9728 /* we go for 3GP style encoding if major brands claims so,
9729 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
9730 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
9731 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
9732 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
9734 /* 16-bit Language code is ignored here as well */
9735 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
9742 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
9743 ret = FALSE; /* may have to fallback */
9748 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
9749 charset, NULL, NULL, &err);
9751 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
9752 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
9757 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
9758 len - offset, env_vars);
9761 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
9762 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s, NULL);
9766 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
9773 qtdemux_tag_add_str (GstQTDemux * qtdemux, const char *tag,
9774 const char *dummy, GNode * node)
9776 qtdemux_tag_add_str_full (qtdemux, tag, dummy, node);
9780 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, const char *tag,
9781 const char *dummy, GNode * node)
9783 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
9785 char *s, *t, *k = NULL;
9790 /* first try normal string tag if major brand not 3GP */
9791 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
9792 if (!qtdemux_tag_add_str_full (qtdemux, tag, dummy, node)) {
9793 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
9794 * let's try it 3gpp way after minor safety check */
9796 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
9802 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
9806 len = QT_UINT32 (data);
9810 count = QT_UINT8 (data + 14);
9812 for (; count; count--) {
9815 if (offset + 1 > len)
9817 slen = QT_UINT8 (data + offset);
9819 if (offset + slen > len)
9821 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
9824 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
9826 t = g_strjoin (",", k, s, NULL);
9834 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
9841 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
9842 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, k, NULL);
9851 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
9857 qtdemux_tag_add_num (GstQTDemux * qtdemux, const char *tag1,
9858 const char *tag2, GNode * node)
9865 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9867 len = QT_UINT32 (data->data);
9868 type = QT_UINT32 ((guint8 *) data->data + 8);
9869 if (type == 0x00000000 && len >= 22) {
9870 n1 = QT_UINT16 ((guint8 *) data->data + 18);
9871 n2 = QT_UINT16 ((guint8 *) data->data + 20);
9873 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
9874 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9878 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
9879 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9887 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
9895 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9897 len = QT_UINT32 (data->data);
9898 type = QT_UINT32 ((guint8 *) data->data + 8);
9899 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
9900 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
9901 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
9902 n1 = QT_UINT16 ((guint8 *) data->data + 16);
9904 /* do not add bpm=0 */
9905 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
9906 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9907 tag1, (gdouble) n1, NULL);
9914 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, const char *tag1,
9915 const char *dummy, GNode * node)
9922 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9924 len = QT_UINT32 (data->data);
9925 type = QT_UINT32 ((guint8 *) data->data + 8);
9926 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
9927 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
9928 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
9929 num = QT_UINT32 ((guint8 *) data->data + 16);
9931 /* do not add num=0 */
9932 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
9933 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9941 qtdemux_tag_add_covr (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
9949 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9951 len = QT_UINT32 (data->data);
9952 type = QT_UINT32 ((guint8 *) data->data + 8);
9953 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
9954 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
9956 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
9957 len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
9958 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
9959 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9960 tag1, sample, NULL);
9961 gst_sample_unref (sample);
9968 qtdemux_tag_add_date (GstQTDemux * qtdemux, const char *tag, const char *dummy,
9976 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9978 len = QT_UINT32 (data->data);
9979 type = QT_UINT32 ((guint8 *) data->data + 8);
9980 if (type == 0x00000001 && len > 16) {
9981 guint y, m = 1, d = 1;
9984 s = g_strndup ((char *) data->data + 16, len - 16);
9985 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
9986 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
9987 if (ret >= 1 && y > 1500 && y < 3000) {
9990 date = g_date_new_dmy (d, m, y);
9991 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag,
9995 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
10003 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, const char *tag, const char *dummy,
10008 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
10010 /* re-route to normal string tag if major brand says so
10011 * or no data atom and compatible brand suggests so */
10012 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
10013 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
10014 qtdemux_tag_add_str (qtdemux, tag, dummy, node);
10019 guint len, type, n;
10021 len = QT_UINT32 (data->data);
10022 type = QT_UINT32 ((guint8 *) data->data + 8);
10023 if (type == 0x00000000 && len >= 18) {
10024 n = QT_UINT16 ((guint8 *) data->data + 16);
10026 const gchar *genre;
10028 genre = gst_tag_id3_genre_get (n - 1);
10029 if (genre != NULL) {
10030 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
10031 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
10040 qtdemux_add_double_tag_from_str (GstQTDemux * demux, const gchar * tag,
10041 guint8 * data, guint32 datasize)
10046 /* make a copy to have \0 at the end */
10047 datacopy = g_strndup ((gchar *) data, datasize);
10049 /* convert the str to double */
10050 if (sscanf (datacopy, "%lf", &value) == 1) {
10051 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
10052 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_REPLACE, tag, value, NULL);
10054 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
10062 qtdemux_tag_add_revdns (GstQTDemux * demux, const char *tag,
10063 const char *tag_bis, GNode * node)
10072 const gchar *meanstr;
10073 const gchar *namestr;
10075 /* checking the whole ---- atom size for consistency */
10076 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
10077 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
10081 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
10083 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
10087 meansize = QT_UINT32 (mean->data);
10088 if (meansize <= 12) {
10089 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
10092 meanstr = ((gchar *) mean->data) + 12;
10095 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
10097 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
10101 namesize = QT_UINT32 (name->data);
10102 if (namesize <= 12) {
10103 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
10106 namestr = ((gchar *) name->data) + 12;
10114 * uint24 - data type
10118 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
10120 GST_WARNING_OBJECT (demux, "No data atom in this tag");
10123 datasize = QT_UINT32 (data->data);
10124 if (datasize <= 16) {
10125 GST_WARNING_OBJECT (demux, "Data atom too small");
10128 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
10130 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
10131 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
10132 static const struct
10134 const gchar name[28];
10135 const gchar tag[28];
10138 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
10139 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
10140 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
10141 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
10142 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
10143 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
10144 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
10145 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
10149 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
10150 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
10151 switch (gst_tag_get_type (tags[i].tag)) {
10152 case G_TYPE_DOUBLE:
10153 qtdemux_add_double_tag_from_str (demux, tags[i].tag,
10154 ((guint8 *) data->data) + 16, datasize - 16);
10156 case G_TYPE_STRING:
10157 qtdemux_tag_add_str (demux, tags[i].tag, NULL, node);
10166 if (i == G_N_ELEMENTS (tags))
10176 #ifndef GST_DISABLE_GST_DEBUG
10178 gchar *namestr_dbg;
10179 gchar *meanstr_dbg;
10181 meanstr_dbg = g_strndup (meanstr, meansize);
10182 namestr_dbg = g_strndup (namestr, namesize);
10184 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
10185 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
10187 g_free (namestr_dbg);
10188 g_free (meanstr_dbg);
10195 qtdemux_tag_add_id32 (GstQTDemux * demux, const char *tag,
10196 const char *tag_bis, GNode * node)
10201 GstTagList *taglist = NULL;
10203 GST_LOG_OBJECT (demux, "parsing ID32");
10206 len = GST_READ_UINT32_BE (data);
10208 /* need at least full box and language tag */
10212 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
10213 gst_buffer_fill (buf, 0, data + 14, len - 14);
10215 taglist = gst_tag_list_from_id3v2_tag (buf);
10217 GST_LOG_OBJECT (demux, "parsing ok");
10218 gst_tag_list_insert (demux->tag_list, taglist, GST_TAG_MERGE_KEEP);
10220 GST_LOG_OBJECT (demux, "parsing failed");
10224 gst_tag_list_unref (taglist);
10226 gst_buffer_unref (buf);
10229 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux,
10230 const char *tag, const char *tag_bis, GNode * node);
10233 FOURCC_pcst -> if media is a podcast -> bool
10234 FOURCC_cpil -> if media is part of a compilation -> bool
10235 FOURCC_pgap -> if media is part of a gapless context -> bool
10236 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
10239 static const struct
10242 const gchar *gst_tag;
10243 const gchar *gst_tag_bis;
10244 const GstQTDemuxAddTagFunc func;
10247 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
10248 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
10249 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
10250 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
10251 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
10252 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
10253 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
10254 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
10255 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
10256 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
10257 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
10258 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
10259 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
10260 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
10261 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
10262 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
10263 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
10264 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
10265 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
10266 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
10267 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
10268 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
10269 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
10270 qtdemux_tag_add_num}, {
10271 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
10272 qtdemux_tag_add_num}, {
10273 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
10274 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
10275 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
10276 FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
10277 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
10278 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
10279 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
10280 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
10281 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
10282 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
10283 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
10284 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
10285 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
10286 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
10287 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
10288 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
10289 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
10290 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
10291 qtdemux_tag_add_classification}, {
10292 FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
10293 FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
10294 FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
10296 /* This is a special case, some tags are stored in this
10297 * 'reverse dns naming', according to:
10298 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
10301 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
10302 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
10303 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
10307 qtdemux_tag_add_blob (GNode * node, GstQTDemux * demux)
10313 const gchar *style;
10320 len = QT_UINT32 (data);
10321 buf = gst_buffer_new_and_alloc (len);
10322 gst_buffer_fill (buf, 0, data, len);
10324 /* heuristic to determine style of tag */
10325 if (QT_FOURCC (data + 4) == FOURCC_____ ||
10326 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
10328 else if (demux->major_brand == FOURCC_qt__)
10329 style = "quicktime";
10330 /* fall back to assuming iso/3gp tag style */
10334 /* santize the name for the caps. */
10335 for (i = 0; i < 4; i++) {
10336 guint8 d = data[4 + i];
10337 if (g_ascii_isalnum (d))
10338 ndata[i] = g_ascii_tolower (d);
10343 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
10344 ndata[0], ndata[1], ndata[2], ndata[3]);
10345 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
10347 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
10348 sample = gst_sample_new (buf, NULL, NULL, s);
10349 gst_buffer_unref (buf);
10350 g_free (media_type);
10352 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
10355 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_APPEND,
10356 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
10358 gst_sample_unref (sample);
10362 qtdemux_parse_udta (GstQTDemux * qtdemux, GNode * udta)
10370 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
10371 if (meta != NULL) {
10372 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
10373 if (ilst == NULL) {
10374 GST_LOG_OBJECT (qtdemux, "no ilst");
10379 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
10382 GST_DEBUG_OBJECT (qtdemux, "new tag list");
10383 if (!qtdemux->tag_list) {
10384 qtdemux->tag_list = gst_tag_list_new_empty ();
10385 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
10387 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
10391 while (i < G_N_ELEMENTS (add_funcs)) {
10392 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
10396 len = QT_UINT32 (node->data);
10398 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
10399 GST_FOURCC_ARGS (add_funcs[i].fourcc));
10401 add_funcs[i].func (qtdemux, add_funcs[i].gst_tag,
10402 add_funcs[i].gst_tag_bis, node);
10404 g_node_destroy (node);
10410 /* parsed nodes have been removed, pass along remainder as blob */
10411 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
10412 (GNodeForeachFunc) qtdemux_tag_add_blob, qtdemux);
10414 /* parse up XMP_ node if existing */
10415 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
10416 if (xmp_ != NULL) {
10418 GstTagList *taglist;
10420 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
10421 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
10422 taglist = gst_tag_list_from_xmp_buffer (buf);
10423 gst_buffer_unref (buf);
10425 qtdemux_handle_xmp_taglist (qtdemux, taglist);
10427 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
10434 GstStructure *structure; /* helper for sort function */
10436 guint min_req_bitrate;
10437 guint min_req_qt_version;
10441 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
10443 GstQtReference *ref_a = (GstQtReference *) a;
10444 GstQtReference *ref_b = (GstQtReference *) b;
10446 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
10447 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
10449 /* known bitrates go before unknown; higher bitrates go first */
10450 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
10453 /* sort the redirects and post a message for the application.
10456 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
10458 GstQtReference *best;
10461 GValue list_val = { 0, };
10464 g_assert (references != NULL);
10466 references = g_list_sort (references, qtdemux_redirects_sort_func);
10468 best = (GstQtReference *) references->data;
10470 g_value_init (&list_val, GST_TYPE_LIST);
10472 for (l = references; l != NULL; l = l->next) {
10473 GstQtReference *ref = (GstQtReference *) l->data;
10474 GValue struct_val = { 0, };
10476 ref->structure = gst_structure_new ("redirect",
10477 "new-location", G_TYPE_STRING, ref->location, NULL);
10479 if (ref->min_req_bitrate > 0) {
10480 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
10481 ref->min_req_bitrate, NULL);
10484 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
10485 g_value_set_boxed (&struct_val, ref->structure);
10486 gst_value_list_append_value (&list_val, &struct_val);
10487 g_value_unset (&struct_val);
10488 /* don't free anything here yet, since we need best->structure below */
10491 g_assert (best != NULL);
10492 s = gst_structure_copy (best->structure);
10494 if (g_list_length (references) > 1) {
10495 gst_structure_set_value (s, "locations", &list_val);
10498 g_value_unset (&list_val);
10500 for (l = references; l != NULL; l = l->next) {
10501 GstQtReference *ref = (GstQtReference *) l->data;
10503 gst_structure_free (ref->structure);
10504 g_free (ref->location);
10507 g_list_free (references);
10509 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
10510 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
10511 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
10512 qtdemux->posted_redirect = TRUE;
10515 /* look for redirect nodes, collect all redirect information and
10519 qtdemux_parse_redirects (GstQTDemux * qtdemux)
10521 GNode *rmra, *rmda, *rdrf;
10523 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
10525 GList *redirects = NULL;
10527 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
10529 GstQtReference ref = { NULL, NULL, 0, 0 };
10530 GNode *rmdr, *rmvc;
10532 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
10533 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
10534 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
10535 ref.min_req_bitrate);
10538 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
10539 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
10540 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
10542 #ifndef GST_DISABLE_GST_DEBUG
10543 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
10545 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
10547 GST_LOG_OBJECT (qtdemux,
10548 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
10549 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
10550 bitmask, check_type);
10551 if (package == FOURCC_qtim && check_type == 0) {
10552 ref.min_req_qt_version = version;
10556 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
10561 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
10562 ref_data = (guint8 *) rdrf->data + 20;
10563 if (ref_type == FOURCC_alis) {
10564 guint record_len, record_version, fn_len;
10566 /* MacOSX alias record, google for alias-layout.txt */
10567 record_len = QT_UINT16 (ref_data + 4);
10568 record_version = QT_UINT16 (ref_data + 4 + 2);
10569 fn_len = QT_UINT8 (ref_data + 50);
10570 if (record_len > 50 && record_version == 2 && fn_len > 0) {
10571 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
10573 } else if (ref_type == FOURCC_url_) {
10574 ref.location = g_strdup ((gchar *) ref_data);
10576 GST_DEBUG_OBJECT (qtdemux,
10577 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
10578 GST_FOURCC_ARGS (ref_type));
10580 if (ref.location != NULL) {
10581 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
10582 redirects = g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
10584 GST_WARNING_OBJECT (qtdemux,
10585 "Failed to extract redirect location from rdrf atom");
10589 /* look for others */
10590 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
10593 if (redirects != NULL) {
10594 qtdemux_process_redirects (qtdemux, redirects);
10600 static GstTagList *
10601 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
10605 if (tags == NULL) {
10606 tags = gst_tag_list_new_empty ();
10607 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
10610 if (qtdemux->major_brand == FOURCC_mjp2)
10611 fmt = "Motion JPEG 2000";
10612 else if ((qtdemux->major_brand & 0xffff) == GST_MAKE_FOURCC ('3', 'g', 0, 0))
10614 else if (qtdemux->major_brand == FOURCC_qt__)
10616 else if (qtdemux->fragmented)
10619 fmt = "ISO MP4/M4A";
10621 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
10622 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
10624 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
10630 /* we have read th complete moov node now.
10631 * This function parses all of the relevant info, creates the traks and
10632 * prepares all data structures for playback
10635 qtdemux_parse_tree (GstQTDemux * qtdemux)
10641 GstClockTime duration;
10642 guint64 creation_time;
10643 GstDateTime *datetime = NULL;
10646 /* make sure we have a usable taglist */
10647 if (!qtdemux->tag_list) {
10648 qtdemux->tag_list = gst_tag_list_new_empty ();
10649 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
10651 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
10654 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
10655 if (mvhd == NULL) {
10656 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
10657 return qtdemux_parse_redirects (qtdemux);
10660 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
10661 if (version == 1) {
10662 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
10663 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
10664 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
10665 } else if (version == 0) {
10666 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
10667 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
10668 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
10670 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
10674 /* Moving qt creation time (secs since 1904) to unix time */
10675 if (creation_time != 0) {
10676 /* Try to use epoch first as it should be faster and more commonly found */
10677 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
10680 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
10681 /* some data cleansing sanity */
10682 g_get_current_time (&now);
10683 if (now.tv_sec + 24 * 3600 < creation_time) {
10684 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
10686 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
10689 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
10690 GDateTime *dt, *dt_local;
10692 dt = g_date_time_add_seconds (base_dt, creation_time);
10693 dt_local = g_date_time_to_local (dt);
10694 datetime = gst_date_time_new_from_g_date_time (dt_local);
10696 g_date_time_unref (base_dt);
10697 g_date_time_unref (dt);
10701 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
10702 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
10704 gst_date_time_unref (datetime);
10707 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
10708 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
10710 /* check for fragmented file and get some (default) data */
10711 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
10714 GstByteReader mehd_data;
10716 /* let track parsing or anyone know weird stuff might happen ... */
10717 qtdemux->fragmented = TRUE;
10719 /* compensate for total duration */
10720 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
10722 qtdemux_parse_mehd (qtdemux, &mehd_data);
10725 /* set duration in the segment info */
10726 gst_qtdemux_get_duration (qtdemux, &duration);
10728 qtdemux->segment.duration = duration;
10729 /* also do not exceed duration; stop is set that way post seek anyway,
10730 * and segment activation falls back to duration,
10731 * whereas loop only checks stop, so let's align this here as well */
10732 qtdemux->segment.stop = duration;
10735 /* parse all traks */
10736 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
10738 qtdemux_parse_trak (qtdemux, trak);
10739 /* iterate all siblings */
10740 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
10744 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
10746 qtdemux_parse_udta (qtdemux, udta);
10748 GST_LOG_OBJECT (qtdemux, "No udta node found.");
10751 /* maybe also some tags in meta box */
10752 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
10754 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
10755 qtdemux_parse_udta (qtdemux, udta);
10757 GST_LOG_OBJECT (qtdemux, "No meta node found.");
10760 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
10765 /* taken from ffmpeg */
10767 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
10779 len = (len << 7) | (c & 0x7f);
10787 /* this can change the codec originally present in @list */
10789 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
10790 GNode * esds, GstTagList * list)
10792 int len = QT_UINT32 (esds->data);
10793 guint8 *ptr = esds->data;
10794 guint8 *end = ptr + len;
10796 guint8 *data_ptr = NULL;
10798 guint8 object_type_id = 0;
10799 const char *codec_name = NULL;
10800 GstCaps *caps = NULL;
10802 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
10804 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
10806 while (ptr + 1 < end) {
10807 tag = QT_UINT8 (ptr);
10808 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
10810 len = read_descr_size (ptr, end, &ptr);
10811 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
10813 /* Check the stated amount of data is available for reading */
10814 if (len < 0 || ptr + len > end)
10818 case ES_DESCRIPTOR_TAG:
10819 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
10820 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
10823 case DECODER_CONFIG_DESC_TAG:{
10824 guint max_bitrate, avg_bitrate;
10826 object_type_id = QT_UINT8 (ptr);
10827 max_bitrate = QT_UINT32 (ptr + 5);
10828 avg_bitrate = QT_UINT32 (ptr + 9);
10829 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
10830 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
10831 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
10832 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
10833 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
10834 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
10835 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
10836 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
10838 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
10839 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
10840 avg_bitrate, NULL);
10845 case DECODER_SPECIFIC_INFO_TAG:
10846 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
10847 if (object_type_id == 0xe0 && len == 0x40) {
10853 GST_DEBUG_OBJECT (qtdemux,
10854 "Have VOBSUB palette. Creating palette event");
10855 /* move to decConfigDescr data and read palette */
10857 for (i = 0; i < 16; i++) {
10858 clut[i] = QT_UINT32 (data);
10862 s = gst_structure_new ("application/x-gst-dvd", "event",
10863 G_TYPE_STRING, "dvd-spu-clut-change",
10864 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
10865 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
10866 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
10867 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
10868 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
10869 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
10870 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
10871 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
10874 /* store event and trigger custom processing */
10875 stream->pending_event =
10876 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
10878 /* Generic codec_data handler puts it on the caps */
10885 case SL_CONFIG_DESC_TAG:
10886 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
10890 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
10892 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
10898 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
10899 * in use, and should also be used to override some other parameters for some
10901 switch (object_type_id) {
10902 case 0x20: /* MPEG-4 */
10903 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
10904 * profile_and_level_indication */
10905 if (data_ptr != NULL && data_len >= 5 &&
10906 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
10907 gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
10908 data_ptr + 4, data_len - 4);
10910 break; /* Nothing special needed here */
10911 case 0x21: /* H.264 */
10912 codec_name = "H.264 / AVC";
10913 caps = gst_caps_new_simple ("video/x-h264",
10914 "stream-format", G_TYPE_STRING, "avc",
10915 "alignment", G_TYPE_STRING, "au", NULL);
10917 case 0x40: /* AAC (any) */
10918 case 0x66: /* AAC Main */
10919 case 0x67: /* AAC LC */
10920 case 0x68: /* AAC SSR */
10921 /* Override channels and rate based on the codec_data, as it's often
10923 /* Only do so for basic setup without HE-AAC extension */
10924 if (data_ptr && data_len == 2) {
10925 guint channels, rateindex, rate;
10927 /* FIXME: add gst_codec_utils_aac_get_{channels|sample_rate}()? */
10928 channels = (data_ptr[1] & 0x7f) >> 3;
10929 if (channels > 0 && channels < 7) {
10930 stream->n_channels = channels;
10931 } else if (channels == 7) {
10932 stream->n_channels = 8;
10935 rateindex = ((data_ptr[0] & 0x7) << 1) | ((data_ptr[1] & 0x80) >> 7);
10936 rate = gst_codec_utils_aac_get_sample_rate_from_index (rateindex);
10938 stream->rate = rate;
10941 /* Set level and profile if possible */
10942 if (data_ptr != NULL && data_len >= 2) {
10943 gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
10944 data_ptr, data_len);
10947 case 0x60: /* MPEG-2, various profiles */
10953 codec_name = "MPEG-2 video";
10954 caps = gst_caps_new_simple ("video/mpeg",
10955 "mpegversion", G_TYPE_INT, 2,
10956 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
10958 case 0x69: /* MPEG-2 BC audio */
10959 case 0x6B: /* MPEG-1 audio */
10960 caps = gst_caps_new_simple ("audio/mpeg",
10961 "mpegversion", G_TYPE_INT, 1, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
10962 codec_name = "MPEG-1 audio";
10964 case 0x6A: /* MPEG-1 */
10965 codec_name = "MPEG-1 video";
10966 caps = gst_caps_new_simple ("video/mpeg",
10967 "mpegversion", G_TYPE_INT, 1,
10968 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
10970 case 0x6C: /* MJPEG */
10972 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
10974 codec_name = "Motion-JPEG";
10976 case 0x6D: /* PNG */
10978 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
10980 codec_name = "PNG still images";
10982 case 0x6E: /* JPEG2000 */
10983 codec_name = "JPEG-2000";
10984 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
10986 case 0xA4: /* Dirac */
10987 codec_name = "Dirac";
10988 caps = gst_caps_new_empty_simple ("video/x-dirac");
10990 case 0xA5: /* AC3 */
10991 codec_name = "AC-3 audio";
10992 caps = gst_caps_new_simple ("audio/x-ac3",
10993 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
10995 case 0xA9: /* AC3 */
10996 codec_name = "DTS audio";
10997 caps = gst_caps_new_simple ("audio/x-dts",
10998 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
11000 case 0xE1: /* QCELP */
11001 /* QCELP, the codec_data is a riff tag (little endian) with
11002 * 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). */
11003 caps = gst_caps_new_empty_simple ("audio/qcelp");
11004 codec_name = "QCELP";
11010 /* If we have a replacement caps, then change our caps for this stream */
11012 gst_caps_unref (stream->caps);
11013 stream->caps = caps;
11016 if (codec_name && list)
11017 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
11018 GST_TAG_AUDIO_CODEC, codec_name, NULL);
11020 /* Add the codec_data attribute to caps, if we have it */
11024 buffer = gst_buffer_new_and_alloc (data_len);
11025 gst_buffer_fill (buffer, 0, data_ptr, data_len);
11027 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
11028 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
11030 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
11032 gst_buffer_unref (buffer);
11037 #define _codec(name) \
11039 if (codec_name) { \
11040 *codec_name = g_strdup (name); \
11045 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
11046 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
11048 GstCaps *caps = NULL;
11049 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
11052 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
11053 _codec ("PNG still images");
11054 caps = gst_caps_new_empty_simple ("image/png");
11056 case GST_MAKE_FOURCC ('j', 'p', 'e', 'g'):
11057 _codec ("JPEG still images");
11059 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
11062 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
11063 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
11064 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
11065 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
11066 _codec ("Motion-JPEG");
11068 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
11071 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
11072 _codec ("Motion-JPEG format B");
11073 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
11075 case GST_MAKE_FOURCC ('m', 'j', 'p', '2'):
11076 _codec ("JPEG-2000");
11077 /* override to what it should be according to spec, avoid palette_data */
11078 stream->bits_per_sample = 24;
11079 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
11081 case GST_MAKE_FOURCC ('S', 'V', 'Q', '3'):
11082 _codec ("Sorensen video v.3");
11083 caps = gst_caps_new_simple ("video/x-svq",
11084 "svqversion", G_TYPE_INT, 3, NULL);
11086 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
11087 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
11088 _codec ("Sorensen video v.1");
11089 caps = gst_caps_new_simple ("video/x-svq",
11090 "svqversion", G_TYPE_INT, 1, NULL);
11092 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
11093 caps = gst_caps_new_empty_simple ("video/x-raw");
11094 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
11095 _codec ("Windows Raw RGB");
11097 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
11101 bps = QT_UINT16 (stsd_data + 98);
11104 format = GST_VIDEO_FORMAT_RGB15;
11107 format = GST_VIDEO_FORMAT_RGB16;
11110 format = GST_VIDEO_FORMAT_RGB;
11113 format = GST_VIDEO_FORMAT_ARGB;
11121 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
11122 format = GST_VIDEO_FORMAT_I420;
11124 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
11125 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
11126 format = GST_VIDEO_FORMAT_I420;
11128 case GST_MAKE_FOURCC ('2', 'v', 'u', 'y'):
11129 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
11130 format = GST_VIDEO_FORMAT_UYVY;
11132 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
11133 format = GST_VIDEO_FORMAT_v308;
11135 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
11136 format = GST_VIDEO_FORMAT_v216;
11138 case GST_MAKE_FOURCC ('v', '2', '1', '0'):
11139 format = GST_VIDEO_FORMAT_v210;
11141 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
11142 format = GST_VIDEO_FORMAT_r210;
11144 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
11145 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
11146 format = GST_VIDEO_FORMAT_v410;
11149 /* Packed YUV 4:4:4:4 8 bit in 32 bits
11150 * but different order than AYUV
11151 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
11152 format = GST_VIDEO_FORMAT_v408;
11155 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
11156 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
11157 _codec ("MPEG-1 video");
11158 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
11159 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11161 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
11162 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
11163 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
11164 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
11165 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
11166 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
11167 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
11168 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
11169 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
11170 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
11171 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
11172 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
11173 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
11174 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
11175 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
11176 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
11177 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
11178 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
11179 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
11180 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
11181 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
11182 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
11183 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
11184 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
11185 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
11186 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
11187 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
11188 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
11189 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
11190 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
11191 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
11192 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
11193 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
11194 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
11195 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
11196 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
11197 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
11198 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
11199 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
11200 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
11201 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
11202 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
11203 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
11204 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
11205 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
11206 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
11207 _codec ("MPEG-2 video");
11208 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
11209 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11211 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
11212 _codec ("GIF still images");
11213 caps = gst_caps_new_empty_simple ("image/gif");
11215 case GST_MAKE_FOURCC ('h', '2', '6', '3'):
11216 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
11217 case GST_MAKE_FOURCC ('s', '2', '6', '3'):
11218 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
11220 /* ffmpeg uses the height/width props, don't know why */
11221 caps = gst_caps_new_simple ("video/x-h263",
11222 "variant", G_TYPE_STRING, "itu", NULL);
11224 case GST_MAKE_FOURCC ('m', 'p', '4', 'v'):
11225 case GST_MAKE_FOURCC ('M', 'P', '4', 'V'):
11226 _codec ("MPEG-4 video");
11227 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
11228 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11230 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
11231 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
11232 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
11233 caps = gst_caps_new_simple ("video/x-msmpeg",
11234 "msmpegversion", G_TYPE_INT, 43, NULL);
11236 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
11238 caps = gst_caps_new_simple ("video/x-divx",
11239 "divxversion", G_TYPE_INT, 3, NULL);
11241 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
11242 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
11244 caps = gst_caps_new_simple ("video/x-divx",
11245 "divxversion", G_TYPE_INT, 4, NULL);
11247 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
11249 caps = gst_caps_new_simple ("video/x-divx",
11250 "divxversion", G_TYPE_INT, 5, NULL);
11253 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
11254 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
11255 case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
11256 case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
11257 case GST_MAKE_FOURCC ('F', 'M', 'P', '4'):
11258 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
11259 caps = gst_caps_new_simple ("video/mpeg",
11260 "mpegversion", G_TYPE_INT, 4, NULL);
11262 *codec_name = g_strdup ("MPEG-4");
11265 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
11266 _codec ("Cinepak");
11267 caps = gst_caps_new_empty_simple ("video/x-cinepak");
11269 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
11270 _codec ("Apple QuickDraw");
11271 caps = gst_caps_new_empty_simple ("video/x-qdrw");
11273 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
11274 _codec ("Apple video");
11275 caps = gst_caps_new_empty_simple ("video/x-apple-video");
11277 case GST_MAKE_FOURCC ('H', '2', '6', '4'):
11278 case GST_MAKE_FOURCC ('a', 'v', 'c', '1'):
11279 _codec ("H.264 / AVC");
11280 caps = gst_caps_new_simple ("video/x-h264",
11281 "stream-format", G_TYPE_STRING, "avc",
11282 "alignment", G_TYPE_STRING, "au", NULL);
11284 case GST_MAKE_FOURCC ('a', 'v', 'c', '3'):
11285 _codec ("H.264 / AVC");
11286 caps = gst_caps_new_simple ("video/x-h264",
11287 "stream-format", G_TYPE_STRING, "avc3",
11288 "alignment", G_TYPE_STRING, "au", NULL);
11290 case GST_MAKE_FOURCC ('H', '2', '6', '5'):
11291 case GST_MAKE_FOURCC ('h', 'v', 'c', '1'):
11292 _codec ("H.265 / HEVC");
11293 caps = gst_caps_new_simple ("video/x-h265",
11294 "stream-format", G_TYPE_STRING, "hvc1",
11295 "alignment", G_TYPE_STRING, "au", NULL);
11297 case GST_MAKE_FOURCC ('h', 'e', 'v', '1'):
11298 _codec ("H.265 / HEVC");
11299 caps = gst_caps_new_simple ("video/x-h265",
11300 "stream-format", G_TYPE_STRING, "hev1",
11301 "alignment", G_TYPE_STRING, "au", NULL);
11303 case GST_MAKE_FOURCC ('r', 'l', 'e', ' '):
11304 _codec ("Run-length encoding");
11305 caps = gst_caps_new_simple ("video/x-rle",
11306 "layout", G_TYPE_STRING, "quicktime", NULL);
11308 case GST_MAKE_FOURCC ('W', 'R', 'L', 'E'):
11309 _codec ("Run-length encoding");
11310 caps = gst_caps_new_simple ("video/x-rle",
11311 "layout", G_TYPE_STRING, "microsoft", NULL);
11313 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
11314 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
11315 _codec ("Indeo Video 3");
11316 caps = gst_caps_new_simple ("video/x-indeo",
11317 "indeoversion", G_TYPE_INT, 3, NULL);
11319 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
11320 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
11321 _codec ("Intel Video 4");
11322 caps = gst_caps_new_simple ("video/x-indeo",
11323 "indeoversion", G_TYPE_INT, 4, NULL);
11325 case GST_MAKE_FOURCC ('d', 'v', 'c', 'p'):
11326 case GST_MAKE_FOURCC ('d', 'v', 'c', ' '):
11327 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
11328 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
11329 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
11330 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
11331 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
11332 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
11333 _codec ("DV Video");
11334 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
11335 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11337 case GST_MAKE_FOURCC ('d', 'v', '5', 'n'): /* DVCPRO50 NTSC */
11338 case GST_MAKE_FOURCC ('d', 'v', '5', 'p'): /* DVCPRO50 PAL */
11339 _codec ("DVCPro50 Video");
11340 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
11341 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11343 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
11344 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
11345 _codec ("DVCProHD Video");
11346 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
11347 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11349 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
11350 _codec ("Apple Graphics (SMC)");
11351 caps = gst_caps_new_empty_simple ("video/x-smc");
11353 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
11355 caps = gst_caps_new_empty_simple ("video/x-vp3");
11357 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
11358 _codec ("VP6 Flash");
11359 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
11361 case GST_MAKE_FOURCC ('X', 'i', 'T', 'h'):
11363 caps = gst_caps_new_empty_simple ("video/x-theora");
11364 /* theora uses one byte of padding in the data stream because it does not
11365 * allow 0 sized packets while theora does */
11366 stream->padding = 1;
11368 case GST_MAKE_FOURCC ('d', 'r', 'a', 'c'):
11370 caps = gst_caps_new_empty_simple ("video/x-dirac");
11372 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
11373 _codec ("TIFF still images");
11374 caps = gst_caps_new_empty_simple ("image/tiff");
11376 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
11377 _codec ("Apple Intermediate Codec");
11378 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
11380 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
11381 _codec ("AVID DNxHD");
11382 caps = gst_caps_from_string ("video/x-dnxhd");
11384 case GST_MAKE_FOURCC ('V', 'P', '8', '0'):
11385 _codec ("On2 VP8");
11386 caps = gst_caps_from_string ("video/x-vp8");
11388 case GST_MAKE_FOURCC ('a', 'p', 'c', 's'):
11389 _codec ("Apple ProRes LT");
11391 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
11394 case GST_MAKE_FOURCC ('a', 'p', 'c', 'h'):
11395 _codec ("Apple ProRes HQ");
11397 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
11400 case GST_MAKE_FOURCC ('a', 'p', 'c', 'n'):
11401 _codec ("Apple ProRes");
11403 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
11406 case GST_MAKE_FOURCC ('a', 'p', 'c', 'o'):
11407 _codec ("Apple ProRes Proxy");
11409 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
11412 case GST_MAKE_FOURCC ('a', 'p', '4', 'h'):
11413 _codec ("Apple ProRes 4444");
11415 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
11418 case GST_MAKE_FOURCC ('v', 'c', '-', '1'):
11421 caps = gst_caps_new_simple ("video/x-wmv",
11422 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
11424 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
11427 char *s, fourstr[5];
11429 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11430 s = g_strdup_printf ("video/x-gst-fourcc-%s", g_strstrip (fourstr));
11431 caps = gst_caps_new_empty_simple (s);
11436 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
11439 gst_video_info_init (&info);
11440 gst_video_info_set_format (&info, format, stream->width, stream->height);
11441 caps = gst_video_info_to_caps (&info);
11442 *codec_name = gst_pb_utils_get_codec_description (caps);
11444 /* enable clipping for raw video streams */
11445 stream->need_clip = TRUE;
11452 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
11453 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
11456 const GstStructure *s;
11460 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
11463 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
11464 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
11465 _codec ("Raw 8-bit PCM audio");
11466 caps = gst_caps_new_simple ("audio/x-raw",
11467 "format", G_TYPE_STRING, "U8",
11468 "layout", G_TYPE_STRING, "interleaved", NULL);
11470 case GST_MAKE_FOURCC ('t', 'w', 'o', 's'):
11471 endian = G_BIG_ENDIAN;
11473 case GST_MAKE_FOURCC ('s', 'o', 'w', 't'):
11477 GstAudioFormat format;
11480 endian = G_LITTLE_ENDIAN;
11482 depth = stream->bytes_per_packet * 8;
11483 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
11485 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
11489 caps = gst_caps_new_simple ("audio/x-raw",
11490 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
11491 "layout", G_TYPE_STRING, "interleaved", NULL);
11494 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
11495 _codec ("Raw 64-bit floating-point audio");
11496 caps = gst_caps_new_simple ("audio/x-raw",
11497 "format", G_TYPE_STRING, "F64BE",
11498 "layout", G_TYPE_STRING, "interleaved", NULL);
11500 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
11501 _codec ("Raw 32-bit floating-point audio");
11502 caps = gst_caps_new_simple ("audio/x-raw",
11503 "format", G_TYPE_STRING, "F32BE",
11504 "layout", G_TYPE_STRING, "interleaved", NULL);
11507 _codec ("Raw 24-bit PCM audio");
11508 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
11510 caps = gst_caps_new_simple ("audio/x-raw",
11511 "format", G_TYPE_STRING, "S24BE",
11512 "layout", G_TYPE_STRING, "interleaved", NULL);
11514 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
11515 _codec ("Raw 32-bit PCM audio");
11516 caps = gst_caps_new_simple ("audio/x-raw",
11517 "format", G_TYPE_STRING, "S32BE",
11518 "layout", G_TYPE_STRING, "interleaved", NULL);
11520 case GST_MAKE_FOURCC ('u', 'l', 'a', 'w'):
11521 _codec ("Mu-law audio");
11522 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
11524 case GST_MAKE_FOURCC ('a', 'l', 'a', 'w'):
11525 _codec ("A-law audio");
11526 caps = gst_caps_new_empty_simple ("audio/x-alaw");
11530 _codec ("Microsoft ADPCM");
11531 /* Microsoft ADPCM-ACM code 2 */
11532 caps = gst_caps_new_simple ("audio/x-adpcm",
11533 "layout", G_TYPE_STRING, "microsoft", NULL);
11537 _codec ("DVI/IMA ADPCM");
11538 caps = gst_caps_new_simple ("audio/x-adpcm",
11539 "layout", G_TYPE_STRING, "dvi", NULL);
11543 _codec ("DVI/Intel IMA ADPCM");
11544 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
11545 caps = gst_caps_new_simple ("audio/x-adpcm",
11546 "layout", G_TYPE_STRING, "quicktime", NULL);
11550 /* MPEG layer 3, CBR only (pre QT4.1) */
11551 case GST_MAKE_FOURCC ('.', 'm', 'p', '3'):
11552 _codec ("MPEG-1 layer 3");
11553 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
11554 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
11555 "mpegversion", G_TYPE_INT, 1, NULL);
11558 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
11559 _codec ("EAC-3 audio");
11560 caps = gst_caps_new_simple ("audio/x-eac3",
11561 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
11562 stream->sampled = TRUE;
11564 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
11565 case GST_MAKE_FOURCC ('a', 'c', '-', '3'):
11566 _codec ("AC-3 audio");
11567 caps = gst_caps_new_simple ("audio/x-ac3",
11568 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
11569 stream->sampled = TRUE;
11571 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
11572 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
11573 _codec ("DTS audio");
11574 caps = gst_caps_new_simple ("audio/x-dts",
11575 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
11576 stream->sampled = TRUE;
11578 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
11579 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
11580 _codec ("DTS-HD audio");
11581 caps = gst_caps_new_simple ("audio/x-dts",
11582 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
11583 stream->sampled = TRUE;
11585 case GST_MAKE_FOURCC ('M', 'A', 'C', '3'):
11587 caps = gst_caps_new_simple ("audio/x-mace",
11588 "maceversion", G_TYPE_INT, 3, NULL);
11590 case GST_MAKE_FOURCC ('M', 'A', 'C', '6'):
11592 caps = gst_caps_new_simple ("audio/x-mace",
11593 "maceversion", G_TYPE_INT, 6, NULL);
11595 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
11597 caps = gst_caps_new_empty_simple ("application/ogg");
11599 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
11600 _codec ("DV audio");
11601 caps = gst_caps_new_empty_simple ("audio/x-dv");
11603 case GST_MAKE_FOURCC ('m', 'p', '4', 'a'):
11604 _codec ("MPEG-4 AAC audio");
11605 caps = gst_caps_new_simple ("audio/mpeg",
11606 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
11607 "stream-format", G_TYPE_STRING, "raw", NULL);
11609 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
11610 _codec ("QDesign Music");
11611 caps = gst_caps_new_empty_simple ("audio/x-qdm");
11613 case GST_MAKE_FOURCC ('Q', 'D', 'M', '2'):
11614 _codec ("QDesign Music v.2");
11615 /* FIXME: QDesign music version 2 (no constant) */
11616 if (FALSE && data) {
11617 caps = gst_caps_new_simple ("audio/x-qdm2",
11618 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
11619 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
11620 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
11622 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
11625 case GST_MAKE_FOURCC ('a', 'g', 's', 'm'):
11626 _codec ("GSM audio");
11627 caps = gst_caps_new_empty_simple ("audio/x-gsm");
11629 case GST_MAKE_FOURCC ('s', 'a', 'm', 'r'):
11630 _codec ("AMR audio");
11631 caps = gst_caps_new_empty_simple ("audio/AMR");
11633 case GST_MAKE_FOURCC ('s', 'a', 'w', 'b'):
11634 _codec ("AMR-WB audio");
11635 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
11637 case GST_MAKE_FOURCC ('i', 'm', 'a', '4'):
11638 _codec ("Quicktime IMA ADPCM");
11639 caps = gst_caps_new_simple ("audio/x-adpcm",
11640 "layout", G_TYPE_STRING, "quicktime", NULL);
11642 case GST_MAKE_FOURCC ('a', 'l', 'a', 'c'):
11643 _codec ("Apple lossless audio");
11644 caps = gst_caps_new_empty_simple ("audio/x-alac");
11646 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
11647 _codec ("QualComm PureVoice");
11648 caps = gst_caps_from_string ("audio/qcelp");
11650 case GST_MAKE_FOURCC ('w', 'm', 'a', ' '):
11653 caps = gst_caps_new_empty_simple ("audio/x-wma");
11655 case GST_MAKE_FOURCC ('l', 'p', 'c', 'm'):
11660 GstAudioFormat format;
11663 FLAG_IS_FLOAT = 0x1,
11664 FLAG_IS_BIG_ENDIAN = 0x2,
11665 FLAG_IS_SIGNED = 0x4,
11666 FLAG_IS_PACKED = 0x8,
11667 FLAG_IS_ALIGNED_HIGH = 0x10,
11668 FLAG_IS_NON_INTERLEAVED = 0x20
11670 _codec ("Raw LPCM audio");
11672 if (data && len >= 56) {
11673 depth = QT_UINT32 (data + 40);
11674 flags = QT_UINT32 (data + 44);
11675 width = QT_UINT32 (data + 48) * 8 / stream->n_channels;
11677 if ((flags & FLAG_IS_FLOAT) == 0) {
11682 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
11683 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
11684 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
11685 caps = gst_caps_new_simple ("audio/x-raw",
11686 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
11687 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
11688 "non-interleaved" : "interleaved", NULL);
11693 if (flags & FLAG_IS_BIG_ENDIAN)
11694 format = GST_AUDIO_FORMAT_F64BE;
11696 format = GST_AUDIO_FORMAT_F64LE;
11698 if (flags & FLAG_IS_BIG_ENDIAN)
11699 format = GST_AUDIO_FORMAT_F32BE;
11701 format = GST_AUDIO_FORMAT_F32LE;
11703 caps = gst_caps_new_simple ("audio/x-raw",
11704 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
11705 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
11706 "non-interleaved" : "interleaved", NULL);
11710 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
11714 char *s, fourstr[5];
11716 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11717 s = g_strdup_printf ("audio/x-gst-fourcc-%s", g_strstrip (fourstr));
11718 caps = gst_caps_new_empty_simple (s);
11724 GstCaps *templ_caps =
11725 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
11726 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
11727 gst_caps_unref (caps);
11728 gst_caps_unref (templ_caps);
11729 caps = intersection;
11732 /* enable clipping for raw audio streams */
11733 s = gst_caps_get_structure (caps, 0);
11734 name = gst_structure_get_name (s);
11735 if (g_str_has_prefix (name, "audio/x-raw")) {
11736 stream->need_clip = TRUE;
11737 stream->max_buffer_size = 4096 * stream->bytes_per_frame;
11738 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
11744 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
11745 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
11749 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
11752 case GST_MAKE_FOURCC ('m', 'p', '4', 's'):
11753 _codec ("DVD subtitle");
11754 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
11755 stream->need_process = TRUE;
11757 case GST_MAKE_FOURCC ('t', 'e', 'x', 't'):
11758 _codec ("Quicktime timed text");
11760 case GST_MAKE_FOURCC ('t', 'x', '3', 'g'):
11761 _codec ("3GPP timed text");
11763 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
11765 /* actual text piece needs to be extracted */
11766 stream->need_process = TRUE;
11770 char *s, fourstr[5];
11772 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11773 s = g_strdup_printf ("text/x-gst-fourcc-%s", g_strstrip (fourstr));
11774 caps = gst_caps_new_empty_simple (s);
11782 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
11783 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
11788 case GST_MAKE_FOURCC ('m', '1', 'v', ' '):
11789 _codec ("MPEG 1 video");
11790 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
11791 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);