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) {
4426 GST_OBJECT_UNLOCK (qtdemux);
4430 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
4431 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
4432 GST_TIME_ARGS (qtdemux->streams[0]->time_position),
4433 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
4435 qtdemux->moof_offset = best_entry->moof_offset;
4437 qtdemux_add_fragmented_samples (qtdemux);
4439 GST_OBJECT_UNLOCK (qtdemux);
4443 static GstFlowReturn
4444 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
4446 GstFlowReturn ret = GST_FLOW_OK;
4447 GstBuffer *buf = NULL;
4448 QtDemuxStream *stream;
4449 GstClockTime min_time;
4451 GstClockTime dts = GST_CLOCK_TIME_NONE;
4452 GstClockTime pts = GST_CLOCK_TIME_NONE;
4453 GstClockTime duration = 0;
4454 gboolean keyframe = FALSE;
4455 guint sample_size = 0;
4461 gst_qtdemux_push_pending_newsegment (qtdemux);
4463 if (qtdemux->fragmented_seek_pending) {
4464 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
4465 gst_qtdemux_do_fragmented_seek (qtdemux);
4466 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
4467 qtdemux->fragmented_seek_pending = FALSE;
4470 /* Figure out the next stream sample to output, min_time is expressed in
4471 * global time and runs over the edit list segments. */
4472 min_time = G_MAXUINT64;
4474 for (i = 0; i < qtdemux->n_streams; i++) {
4475 GstClockTime position;
4477 stream = qtdemux->streams[i];
4478 position = stream->time_position;
4480 /* position of -1 is EOS */
4481 if (position != GST_CLOCK_TIME_NONE && position < min_time) {
4482 min_time = position;
4487 if (G_UNLIKELY (index == -1)) {
4488 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
4492 /* check for segment end */
4493 if (G_UNLIKELY (qtdemux->segment.stop != -1
4494 && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
4495 || (qtdemux->segment.rate < 0
4496 && qtdemux->segment.start > min_time))
4497 && qtdemux->streams[index]->on_keyframe)) {
4498 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
4499 qtdemux->streams[index]->time_position = GST_CLOCK_TIME_NONE;
4503 /* gap events for subtitle streams */
4504 for (i = 0; i < qtdemux->n_streams; i++) {
4505 stream = qtdemux->streams[i];
4506 if (stream->pad && (stream->subtype == FOURCC_subp
4507 || stream->subtype == FOURCC_text
4508 || stream->subtype == FOURCC_sbtl)) {
4509 /* send one second gap events until the stream catches up */
4510 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
4511 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
4512 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
4513 stream->segment.position + GST_SECOND < min_time) {
4515 gst_event_new_gap (stream->segment.position, GST_SECOND);
4516 gst_pad_push_event (stream->pad, gap);
4517 stream->segment.position += GST_SECOND;
4522 stream = qtdemux->streams[index];
4523 if (stream->new_caps) {
4524 gst_qtdemux_configure_stream (qtdemux, stream);
4525 qtdemux_do_allocation (qtdemux, stream);
4528 /* fetch info for the current sample of this stream */
4529 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
4530 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
4533 GST_DEBUG_OBJECT (qtdemux,
4534 "pushing from stream %d, empty %d offset %" G_GUINT64_FORMAT
4535 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
4536 ", duration %" GST_TIME_FORMAT, index, empty, offset, sample_size,
4537 GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
4539 if (G_UNLIKELY (empty)) {
4540 /* empty segment, push a gap and move to the next one */
4541 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
4542 stream->segment.position = pts + duration;
4546 /* hmm, empty sample, skip and move to next sample */
4547 if (G_UNLIKELY (sample_size <= 0))
4550 /* last pushed sample was out of boundary, goto next sample */
4551 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
4554 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
4557 GST_DEBUG_OBJECT (qtdemux,
4558 "size %d larger than stream max_buffer_size %d, trimming",
4559 sample_size, stream->max_buffer_size);
4561 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
4564 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
4567 if (stream->use_allocator) {
4568 /* if we have a per-stream allocator, use it */
4569 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
4572 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
4574 if (G_UNLIKELY (ret != GST_FLOW_OK))
4577 if (size != sample_size) {
4578 pts += gst_util_uint64_scale_int (GST_SECOND,
4579 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
4580 dts += gst_util_uint64_scale_int (GST_SECOND,
4581 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
4582 duration = gst_util_uint64_scale_int (GST_SECOND,
4583 size / stream->bytes_per_frame, stream->timescale);
4586 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
4587 dts, pts, duration, keyframe, min_time, offset);
4589 if (size != sample_size) {
4590 QtDemuxSample *sample = &stream->samples[stream->sample_index];
4591 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
4593 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
4594 sample->timestamp + stream->offset_in_sample / stream->bytes_per_frame);
4595 if (time_position >= segment->media_start) {
4596 /* inside the segment, update time_position, looks very familiar to
4597 * GStreamer segments, doesn't it? */
4598 stream->time_position = (time_position - segment->media_start) +
4601 /* not yet in segment, time does not yet increment. This means
4602 * that we are still prerolling keyframes to the decoder so it can
4603 * decode the first sample of the segment. */
4604 stream->time_position = segment->time;
4609 ret = gst_qtdemux_combine_flows (qtdemux, ret);
4610 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
4611 * we have no more data for the pad to push */
4612 if (ret == GST_FLOW_EOS)
4615 stream->offset_in_sample += size;
4616 if (stream->offset_in_sample >= sample_size) {
4617 gst_qtdemux_advance_sample (qtdemux, stream);
4622 gst_qtdemux_advance_sample (qtdemux, stream);
4630 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
4636 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
4637 /* EOS will be raised if all are EOS */
4644 gst_qtdemux_loop (GstPad * pad)
4646 GstQTDemux *qtdemux;
4650 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
4652 cur_offset = qtdemux->offset;
4653 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %d",
4654 cur_offset, qtdemux->state);
4656 switch (qtdemux->state) {
4657 case QTDEMUX_STATE_INITIAL:
4658 case QTDEMUX_STATE_HEADER:
4659 ret = gst_qtdemux_loop_state_header (qtdemux);
4661 case QTDEMUX_STATE_MOVIE:
4662 ret = gst_qtdemux_loop_state_movie (qtdemux);
4663 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
4664 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
4672 /* if something went wrong, pause */
4673 if (ret != GST_FLOW_OK)
4677 gst_object_unref (qtdemux);
4683 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
4684 (NULL), ("streaming stopped, invalid state"));
4685 gst_pad_pause_task (pad);
4686 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
4691 const gchar *reason = gst_flow_get_name (ret);
4693 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
4695 gst_pad_pause_task (pad);
4697 /* fatal errors need special actions */
4699 if (ret == GST_FLOW_EOS) {
4700 if (qtdemux->n_streams == 0) {
4701 /* we have no streams, post an error */
4702 gst_qtdemux_post_no_playable_stream_error (qtdemux);
4704 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
4707 if ((stop = qtdemux->segment.stop) == -1)
4708 stop = qtdemux->segment.duration;
4710 if (qtdemux->segment.rate >= 0) {
4711 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
4712 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
4713 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
4714 GST_FORMAT_TIME, stop));
4715 gst_qtdemux_push_event (qtdemux,
4716 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
4718 /* For Reverse Playback */
4719 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
4720 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
4721 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
4722 GST_FORMAT_TIME, qtdemux->segment.start));
4723 gst_qtdemux_push_event (qtdemux,
4724 gst_event_new_segment_done (GST_FORMAT_TIME,
4725 qtdemux->segment.start));
4728 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
4729 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
4731 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
4732 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
4733 (NULL), ("streaming stopped, reason %s", reason));
4734 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
4743 * Returns if there are samples to be played.
4746 has_next_entry (GstQTDemux * demux)
4748 QtDemuxStream *stream;
4751 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
4753 for (i = 0; i < demux->n_streams; i++) {
4754 stream = demux->streams[i];
4756 if (stream->sample_index == -1) {
4757 stream->sample_index = 0;
4758 stream->offset_in_sample = 0;
4761 if (stream->sample_index >= stream->n_samples) {
4762 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
4765 GST_DEBUG_OBJECT (demux, "Found a sample");
4769 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
4776 * Returns the size of the first entry at the current offset.
4777 * If -1, there are none (which means EOS or empty file).
4780 next_entry_size (GstQTDemux * demux)
4782 QtDemuxStream *stream;
4785 guint64 smalloffs = (guint64) - 1;
4786 QtDemuxSample *sample;
4788 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
4791 for (i = 0; i < demux->n_streams; i++) {
4792 stream = demux->streams[i];
4794 if (stream->sample_index == -1) {
4795 stream->sample_index = 0;
4796 stream->offset_in_sample = 0;
4799 if (stream->sample_index >= stream->n_samples) {
4800 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
4804 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
4805 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
4806 stream->sample_index);
4810 sample = &stream->samples[stream->sample_index];
4812 GST_LOG_OBJECT (demux,
4813 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
4814 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
4815 sample->offset, sample->size);
4817 if (((smalloffs == -1)
4818 || (sample->offset < smalloffs)) && (sample->size)) {
4820 smalloffs = sample->offset;
4824 GST_LOG_OBJECT (demux,
4825 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
4826 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
4831 stream = demux->streams[smallidx];
4832 sample = &stream->samples[stream->sample_index];
4834 if (sample->offset >= demux->offset) {
4835 demux->todrop = sample->offset - demux->offset;
4836 return sample->size + demux->todrop;
4839 GST_DEBUG_OBJECT (demux,
4840 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
4845 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
4847 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
4849 gst_element_post_message (GST_ELEMENT_CAST (demux),
4850 gst_message_new_element (GST_OBJECT_CAST (demux),
4851 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
4855 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
4860 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
4863 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
4864 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
4865 GST_SEEK_TYPE_NONE, -1);
4867 res = gst_pad_push_event (demux->sinkpad, event);
4872 /* check for seekable upstream, above and beyond a mere query */
4874 gst_qtdemux_check_seekability (GstQTDemux * demux)
4877 gboolean seekable = FALSE;
4878 gint64 start = -1, stop = -1;
4880 if (demux->upstream_size)
4883 query = gst_query_new_seeking (GST_FORMAT_BYTES);
4884 if (!gst_pad_peer_query (demux->sinkpad, query)) {
4885 GST_DEBUG_OBJECT (demux, "seeking query failed");
4889 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
4891 /* try harder to query upstream size if we didn't get it the first time */
4892 if (seekable && stop == -1) {
4893 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
4894 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
4897 /* if upstream doesn't know the size, it's likely that it's not seekable in
4898 * practice even if it technically may be seekable */
4899 if (seekable && (start != 0 || stop <= start)) {
4900 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
4905 gst_query_unref (query);
4907 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
4908 G_GUINT64_FORMAT ")", seekable, start, stop);
4909 demux->upstream_seekable = seekable;
4910 demux->upstream_size = seekable ? stop : -1;
4913 /* FIXME, unverified after edit list updates */
4914 static GstFlowReturn
4915 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
4919 demux = GST_QTDEMUX (parent);
4921 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
4924 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
4926 for (i = 0; i < demux->n_streams; i++) {
4927 demux->streams[i]->discont = TRUE;
4931 gst_adapter_push (demux->adapter, inbuf);
4933 GST_DEBUG_OBJECT (demux,
4934 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
4935 demux->neededbytes, gst_adapter_available (demux->adapter));
4937 return gst_qtdemux_process_adapter (demux, FALSE);
4940 static GstFlowReturn
4941 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
4943 GstFlowReturn ret = GST_FLOW_OK;
4945 /* we never really mean to buffer that much */
4946 if (demux->neededbytes == -1) {
4950 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
4951 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
4953 GST_DEBUG_OBJECT (demux,
4954 "state:%d , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT,
4955 demux->state, demux->neededbytes, demux->offset);
4957 switch (demux->state) {
4958 case QTDEMUX_STATE_INITIAL:{
4963 gst_qtdemux_check_seekability (demux);
4965 data = gst_adapter_map (demux->adapter, demux->neededbytes);
4967 /* get fourcc/length, set neededbytes */
4968 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
4970 gst_adapter_unmap (demux->adapter);
4972 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
4973 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
4975 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4976 (_("This file is invalid and cannot be played.")),
4977 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
4978 GST_FOURCC_ARGS (fourcc)));
4979 ret = GST_FLOW_ERROR;
4982 if (fourcc == FOURCC_mdat) {
4983 gint next_entry = next_entry_size (demux);
4984 if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
4985 /* we have the headers, start playback */
4986 demux->state = QTDEMUX_STATE_MOVIE;
4987 demux->neededbytes = next_entry;
4988 demux->mdatleft = size;
4990 /* no headers yet, try to get them */
4993 guint64 old, target;
4996 old = demux->offset;
4997 target = old + size;
4999 /* try to jump over the atom with a seek */
5000 /* only bother if it seems worth doing so,
5001 * and avoids possible upstream/server problems */
5002 if (demux->upstream_seekable &&
5003 demux->upstream_size > 4 * (1 << 20)) {
5004 res = qtdemux_seek_offset (demux, target);
5006 GST_DEBUG_OBJECT (demux, "skipping seek");
5011 GST_DEBUG_OBJECT (demux, "seek success");
5012 /* remember the offset fo the first mdat so we can seek back to it
5013 * after we have the headers */
5014 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
5015 demux->first_mdat = old;
5016 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
5019 /* seek worked, continue reading */
5020 demux->offset = target;
5021 demux->neededbytes = 16;
5022 demux->state = QTDEMUX_STATE_INITIAL;
5024 /* seek failed, need to buffer */
5025 demux->offset = old;
5026 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
5027 /* there may be multiple mdat (or alike) buffers */
5029 if (demux->mdatbuffer)
5030 bs = gst_buffer_get_size (demux->mdatbuffer);
5033 if (size + bs > 10 * (1 << 20))
5035 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
5036 demux->neededbytes = size;
5037 if (!demux->mdatbuffer)
5038 demux->mdatoffset = demux->offset;
5041 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
5042 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
5043 (_("This file is invalid and cannot be played.")),
5044 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
5045 GST_FOURCC_ARGS (fourcc), size));
5046 ret = GST_FLOW_ERROR;
5049 /* this means we already started buffering and still no moov header,
5050 * let's continue buffering everything till we get moov */
5051 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
5052 || fourcc == FOURCC_moof))
5054 demux->neededbytes = size;
5055 demux->state = QTDEMUX_STATE_HEADER;
5059 case QTDEMUX_STATE_HEADER:{
5063 GST_DEBUG_OBJECT (demux, "In header");
5065 data = gst_adapter_map (demux->adapter, demux->neededbytes);
5067 /* parse the header */
5068 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
5070 if (fourcc == FOURCC_moov) {
5071 /* in usual fragmented setup we could try to scan for more
5072 * and end up at the the moov (after mdat) again */
5073 if (demux->got_moov && demux->n_streams > 0 &&
5075 || demux->last_moov_offset == demux->offset)) {
5076 GST_DEBUG_OBJECT (demux,
5077 "Skipping moov atom as we have (this) one already");
5079 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
5081 if (demux->got_moov && demux->fragmented) {
5082 GST_DEBUG_OBJECT (demux,
5083 "Got a second moov, clean up data from old one");
5084 if (demux->moov_node)
5085 g_node_destroy (demux->moov_node);
5086 demux->moov_node = NULL;
5087 demux->moov_node_compressed = NULL;
5089 /* prepare newsegment to send when streaming actually starts */
5090 if (!demux->pending_newsegment)
5091 demux->pending_newsegment =
5092 gst_event_new_segment (&demux->segment);
5095 demux->last_moov_offset = demux->offset;
5097 qtdemux_parse_moov (demux, data, demux->neededbytes);
5098 qtdemux_node_dump (demux, demux->moov_node);
5099 qtdemux_parse_tree (demux);
5100 qtdemux_prepare_streams (demux);
5101 if (!demux->got_moov)
5102 qtdemux_expose_streams (demux);
5106 for (n = 0; n < demux->n_streams; n++) {
5107 QtDemuxStream *stream = demux->streams[n];
5109 gst_qtdemux_configure_stream (demux, stream);
5113 demux->got_moov = TRUE;
5115 g_node_destroy (demux->moov_node);
5116 demux->moov_node = NULL;
5117 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
5119 } else if (fourcc == FOURCC_moof) {
5120 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
5122 GstClockTime prev_pts;
5123 guint64 prev_offset;
5125 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
5128 * The timestamp of the moof buffer is relevant as some scenarios
5129 * won't have the initial timestamp in the atoms. Whenever a new
5130 * buffer has started, we get that buffer's PTS and use it as a base
5131 * timestamp for the trun entries.
5133 * To keep track of the current buffer timestamp and starting point
5134 * we use gst_adapter_prev_pts that gives us the PTS and the distance
5135 * from the beggining of the buffer, with the distance and demux->offset
5136 * we know if it is still the same buffer or not.
5138 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
5139 prev_offset = demux->offset - dist;
5140 if (demux->fragment_start_offset == -1
5141 || prev_offset > demux->fragment_start_offset) {
5142 demux->fragment_start_offset = prev_offset;
5143 demux->fragment_start = prev_pts;
5144 GST_DEBUG_OBJECT (demux,
5145 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
5146 GST_TIME_FORMAT, demux->fragment_start_offset,
5147 GST_TIME_ARGS (demux->fragment_start));
5150 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
5151 demux->offset, NULL)) {
5152 gst_adapter_unmap (demux->adapter);
5153 ret = GST_FLOW_ERROR;
5156 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
5157 if (demux->mss_mode && !demux->exposed) {
5158 if (!demux->pending_newsegment) {
5160 gst_segment_init (&segment, GST_FORMAT_TIME);
5161 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
5162 demux->pending_newsegment = gst_event_new_segment (&segment);
5164 qtdemux_expose_streams (demux);
5167 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
5169 } else if (fourcc == FOURCC_ftyp) {
5170 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
5171 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
5172 } else if (fourcc == FOURCC_uuid) {
5173 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
5174 qtdemux_parse_uuid (demux, data, demux->neededbytes);
5176 GST_WARNING_OBJECT (demux,
5177 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
5178 GST_FOURCC_ARGS (fourcc));
5179 /* Let's jump that one and go back to initial state */
5181 gst_adapter_unmap (demux->adapter);
5184 if (demux->mdatbuffer && demux->n_streams) {
5185 gsize remaining_data_size = 0;
5187 /* the mdat was before the header */
5188 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
5189 demux->n_streams, demux->mdatbuffer);
5190 /* restore our adapter/offset view of things with upstream;
5191 * put preceding buffered data ahead of current moov data.
5192 * This should also handle evil mdat, moov, mdat cases and alike */
5193 gst_adapter_flush (demux->adapter, demux->neededbytes);
5195 /* Store any remaining data after the mdat for later usage */
5196 remaining_data_size = gst_adapter_available (demux->adapter);
5197 if (remaining_data_size > 0) {
5198 g_assert (demux->restoredata_buffer == NULL);
5199 demux->restoredata_buffer =
5200 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
5201 demux->restoredata_offset = demux->offset + demux->neededbytes;
5202 GST_DEBUG_OBJECT (demux,
5203 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
5204 G_GUINT64_FORMAT, remaining_data_size,
5205 demux->restoredata_offset);
5208 gst_adapter_push (demux->adapter, demux->mdatbuffer);
5209 demux->mdatbuffer = NULL;
5210 demux->offset = demux->mdatoffset;
5211 demux->neededbytes = next_entry_size (demux);
5212 demux->state = QTDEMUX_STATE_MOVIE;
5213 demux->mdatleft = gst_adapter_available (demux->adapter);
5215 GST_DEBUG_OBJECT (demux, "Carrying on normally");
5216 gst_adapter_flush (demux->adapter, demux->neededbytes);
5218 /* only go back to the mdat if there are samples to play */
5219 if (demux->got_moov && demux->first_mdat != -1
5220 && has_next_entry (demux)) {
5223 /* we need to seek back */
5224 res = qtdemux_seek_offset (demux, demux->first_mdat);
5226 demux->offset = demux->first_mdat;
5228 GST_DEBUG_OBJECT (demux, "Seek back failed");
5231 demux->offset += demux->neededbytes;
5233 demux->neededbytes = 16;
5234 demux->state = QTDEMUX_STATE_INITIAL;
5239 case QTDEMUX_STATE_BUFFER_MDAT:{
5243 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
5245 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
5246 gst_buffer_extract (buf, 0, fourcc, 4);
5247 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
5248 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
5249 if (demux->mdatbuffer)
5250 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
5252 demux->mdatbuffer = buf;
5253 demux->offset += demux->neededbytes;
5254 demux->neededbytes = 16;
5255 demux->state = QTDEMUX_STATE_INITIAL;
5256 gst_qtdemux_post_progress (demux, 1, 1);
5260 case QTDEMUX_STATE_MOVIE:{
5262 QtDemuxStream *stream = NULL;
5263 QtDemuxSample *sample;
5265 GstClockTime dts, pts, duration;
5268 GST_DEBUG_OBJECT (demux,
5269 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
5271 if (demux->fragmented) {
5272 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
5274 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
5275 /* if needed data starts within this atom,
5276 * then it should not exceed this atom */
5277 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
5278 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
5279 (_("This file is invalid and cannot be played.")),
5280 ("sample data crosses atom boundary"));
5281 ret = GST_FLOW_ERROR;
5284 demux->mdatleft -= demux->neededbytes;
5286 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
5287 /* so we are dropping more than left in this atom */
5288 demux->todrop -= demux->mdatleft;
5289 demux->neededbytes -= demux->mdatleft;
5290 demux->mdatleft = 0;
5291 /* need to resume atom parsing so we do not miss any other pieces */
5292 demux->state = QTDEMUX_STATE_INITIAL;
5293 demux->neededbytes = 16;
5295 /* check if there was any stored post mdat data from previous buffers */
5296 if (demux->restoredata_buffer) {
5297 g_assert (gst_adapter_available (demux->adapter) == 0);
5299 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
5300 demux->restoredata_buffer = NULL;
5301 demux->offset = demux->restoredata_offset;
5308 if (demux->todrop) {
5309 GST_LOG_OBJECT (demux, "Dropping %d bytes", demux->todrop);
5310 gst_adapter_flush (demux->adapter, demux->todrop);
5311 demux->neededbytes -= demux->todrop;
5312 demux->offset += demux->todrop;
5316 /* initial newsegment sent here after having added pads,
5317 * possible others in sink_event */
5318 if (G_UNLIKELY (demux->pending_newsegment)) {
5319 gst_qtdemux_push_pending_newsegment (demux);
5320 /* clear to send tags on all streams */
5321 for (i = 0; i < demux->n_streams; i++) {
5322 stream = demux->streams[i];
5323 gst_qtdemux_push_tags (demux, stream);
5324 if (stream->sparse) {
5325 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
5326 gst_pad_push_event (stream->pad,
5327 gst_event_new_gap (stream->segment.position,
5328 GST_CLOCK_TIME_NONE));
5333 /* Figure out which stream this packet belongs to */
5334 for (i = 0; i < demux->n_streams; i++) {
5335 stream = demux->streams[i];
5336 if (stream->sample_index >= stream->n_samples)
5338 GST_LOG_OBJECT (demux,
5339 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
5340 " / size:%d)", i, stream->sample_index,
5341 stream->samples[stream->sample_index].offset,
5342 stream->samples[stream->sample_index].size);
5344 if (stream->samples[stream->sample_index].offset == demux->offset)
5348 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
5349 goto unknown_stream;
5351 if (stream->new_caps) {
5352 gst_qtdemux_configure_stream (demux, stream);
5355 /* Put data in a buffer, set timestamps, caps, ... */
5356 sample = &stream->samples[stream->sample_index];
5358 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
5359 outbuf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
5360 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
5361 GST_FOURCC_ARGS (stream->fourcc));
5363 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
5365 dts = QTSAMPLE_DTS (stream, sample);
5366 pts = QTSAMPLE_PTS (stream, sample);
5367 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
5368 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5370 /* check for segment end */
5371 if (G_UNLIKELY (demux->segment.stop != -1
5372 && demux->segment.stop <= pts && stream->on_keyframe)) {
5373 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
5374 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
5376 /* check if all streams are eos */
5378 for (i = 0; i < demux->n_streams; i++) {
5379 if (!STREAM_IS_EOS (demux->streams[i])) {
5385 if (ret == GST_FLOW_EOS) {
5386 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
5390 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
5391 dts, pts, duration, keyframe, dts, demux->offset);
5395 ret = gst_qtdemux_combine_flows (demux, ret);
5397 /* skip this data, stream is EOS */
5398 gst_adapter_flush (demux->adapter, demux->neededbytes);
5401 stream->sample_index++;
5402 stream->offset_in_sample = 0;
5404 /* update current offset and figure out size of next buffer */
5405 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
5406 demux->offset, demux->neededbytes);
5407 demux->offset += demux->neededbytes;
5408 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
5411 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
5412 if (demux->fragmented) {
5413 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
5414 /* there may be more to follow, only finish this atom */
5415 demux->todrop = demux->mdatleft;
5416 demux->neededbytes = demux->todrop;
5428 /* when buffering movie data, at least show user something is happening */
5429 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
5430 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
5431 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
5432 demux->neededbytes);
5441 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
5442 ret = GST_FLOW_ERROR;
5447 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
5453 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
5454 (NULL), ("qtdemuxer invalid state %d", demux->state));
5455 ret = GST_FLOW_ERROR;
5460 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
5461 (NULL), ("no 'moov' atom within the first 10 MB"));
5462 ret = GST_FLOW_ERROR;
5468 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
5473 query = gst_query_new_scheduling ();
5475 if (!gst_pad_peer_query (sinkpad, query)) {
5476 gst_query_unref (query);
5480 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
5481 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
5482 gst_query_unref (query);
5487 GST_DEBUG_OBJECT (sinkpad, "activating pull");
5488 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
5492 GST_DEBUG_OBJECT (sinkpad, "activating push");
5493 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
5498 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
5499 GstPadMode mode, gboolean active)
5502 GstQTDemux *demux = GST_QTDEMUX (parent);
5505 case GST_PAD_MODE_PUSH:
5506 demux->pullbased = FALSE;
5509 case GST_PAD_MODE_PULL:
5511 demux->pullbased = TRUE;
5512 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
5515 res = gst_pad_stop_task (sinkpad);
5527 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
5529 return g_malloc (items * size);
5533 qtdemux_zfree (void *opaque, void *addr)
5539 qtdemux_inflate (void *z_buffer, guint z_length, guint length)
5545 z = g_new0 (z_stream, 1);
5546 z->zalloc = qtdemux_zalloc;
5547 z->zfree = qtdemux_zfree;
5550 z->next_in = z_buffer;
5551 z->avail_in = z_length;
5553 buffer = (guint8 *) g_malloc (length);
5554 ret = inflateInit (z);
5555 while (z->avail_in > 0) {
5556 if (z->avail_out == 0) {
5558 buffer = (guint8 *) g_realloc (buffer, length);
5559 z->next_out = buffer + z->total_out;
5560 z->avail_out = 1024;
5562 ret = inflate (z, Z_SYNC_FLUSH);
5566 if (ret != Z_STREAM_END) {
5567 g_warning ("inflate() returned %d", ret);
5573 #endif /* HAVE_ZLIB */
5576 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
5580 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
5582 /* counts as header data */
5583 qtdemux->header_size += length;
5585 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
5586 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
5588 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
5594 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
5595 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
5596 if (dcom == NULL || cmvd == NULL)
5597 goto invalid_compression;
5599 method = QT_FOURCC ((guint8 *) dcom->data + 8);
5602 case GST_MAKE_FOURCC ('z', 'l', 'i', 'b'):{
5603 guint uncompressed_length;
5604 guint compressed_length;
5607 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
5608 compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12;
5609 GST_LOG ("length = %u", uncompressed_length);
5612 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
5613 compressed_length, uncompressed_length);
5615 qtdemux->moov_node_compressed = qtdemux->moov_node;
5616 qtdemux->moov_node = g_node_new (buf);
5618 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
5619 uncompressed_length);
5622 #endif /* HAVE_ZLIB */
5624 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
5625 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
5632 invalid_compression:
5634 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
5640 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
5643 while (G_UNLIKELY (buf < end)) {
5647 if (G_UNLIKELY (buf + 4 > end)) {
5648 GST_LOG_OBJECT (qtdemux, "buffer overrun");
5651 len = QT_UINT32 (buf);
5652 if (G_UNLIKELY (len == 0)) {
5653 GST_LOG_OBJECT (qtdemux, "empty container");
5656 if (G_UNLIKELY (len < 8)) {
5657 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
5660 if (G_UNLIKELY (len > (end - buf))) {
5661 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
5662 (gint) (end - buf));
5666 child = g_node_new ((guint8 *) buf);
5667 g_node_append (node, child);
5668 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
5669 qtdemux_parse_node (qtdemux, child, buf, len);
5677 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
5680 int len = QT_UINT32 (xdxt->data);
5681 guint8 *buf = xdxt->data;
5682 guint8 *end = buf + len;
5685 /* skip size and type */
5693 size = QT_UINT32 (buf);
5694 type = QT_FOURCC (buf + 4);
5696 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
5698 if (buf + size > end || size <= 0)
5704 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
5705 GST_FOURCC_ARGS (type));
5709 buffer = gst_buffer_new_and_alloc (size);
5710 gst_buffer_fill (buffer, 0, buf, size);
5711 stream->buffers = g_slist_append (stream->buffers, buffer);
5712 GST_LOG_OBJECT (qtdemux, "parsing theora header");
5715 buffer = gst_buffer_new_and_alloc (size);
5716 gst_buffer_fill (buffer, 0, buf, size);
5717 stream->buffers = g_slist_append (stream->buffers, buffer);
5718 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
5721 buffer = gst_buffer_new_and_alloc (size);
5722 gst_buffer_fill (buffer, 0, buf, size);
5723 stream->buffers = g_slist_append (stream->buffers, buffer);
5724 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
5727 GST_WARNING_OBJECT (qtdemux,
5728 "unknown theora cookie %" GST_FOURCC_FORMAT,
5729 GST_FOURCC_ARGS (type));
5738 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
5742 guint32 node_length = 0;
5743 const QtNodeType *type;
5746 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
5748 if (G_UNLIKELY (length < 8))
5749 goto not_enough_data;
5751 node_length = QT_UINT32 (buffer);
5752 fourcc = QT_FOURCC (buffer + 4);
5754 /* ignore empty nodes */
5755 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
5758 type = qtdemux_type_get (fourcc);
5760 end = buffer + length;
5762 GST_LOG_OBJECT (qtdemux,
5763 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
5764 GST_FOURCC_ARGS (fourcc), node_length, type->name);
5766 if (node_length > length)
5767 goto broken_atom_size;
5769 if (type->flags & QT_FLAG_CONTAINER) {
5770 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
5775 if (node_length < 20) {
5776 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
5779 GST_DEBUG_OBJECT (qtdemux,
5780 "parsing stsd (sample table, sample description) atom");
5781 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
5782 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
5792 /* also read alac (or whatever) in stead of mp4a in the following,
5793 * since a similar layout is used in other cases as well */
5794 if (fourcc == FOURCC_mp4a)
5799 /* There are two things we might encounter here: a true mp4a atom, and
5800 an mp4a entry in an stsd atom. The latter is what we're interested
5801 in, and it looks like an atom, but isn't really one. The true mp4a
5802 atom is short, so we detect it based on length here. */
5803 if (length < min_size) {
5804 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
5805 GST_FOURCC_ARGS (fourcc));
5809 /* 'version' here is the sound sample description version. Types 0 and
5810 1 are documented in the QTFF reference, but type 2 is not: it's
5811 described in Apple header files instead (struct SoundDescriptionV2
5813 version = QT_UINT16 (buffer + 16);
5815 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
5816 GST_FOURCC_ARGS (fourcc), version);
5818 /* parse any esds descriptors */
5830 GST_WARNING_OBJECT (qtdemux,
5831 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
5832 GST_FOURCC_ARGS (fourcc), version);
5837 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
5854 /* codec_data is contained inside these atoms, which all have
5855 * the same format. */
5857 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
5858 GST_FOURCC_ARGS (fourcc));
5859 version = QT_UINT32 (buffer + 16);
5860 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
5861 if (1 || version == 0x00000000) {
5862 buf = buffer + 0x32;
5864 /* FIXME Quicktime uses PASCAL string while
5865 * the iso format uses C strings. Check the file
5866 * type before attempting to parse the string here. */
5867 tlen = QT_UINT8 (buf);
5868 GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
5870 GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
5871 /* the string has a reserved space of 32 bytes so skip
5872 * the remaining 31 */
5874 buf += 4; /* and 4 bytes reserved */
5876 GST_MEMDUMP_OBJECT (qtdemux, "mp4v", buf, end - buf);
5878 qtdemux_parse_container (qtdemux, node, buf, end);
5884 GST_MEMDUMP_OBJECT (qtdemux, "H264", buffer, end - buffer);
5885 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
5890 GST_MEMDUMP_OBJECT (qtdemux, "avc1", buffer, end - buffer);
5891 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
5896 GST_MEMDUMP_OBJECT (qtdemux, "avc3", buffer, end - buffer);
5897 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
5902 GST_MEMDUMP_OBJECT (qtdemux, "H265", buffer, end - buffer);
5903 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
5908 GST_MEMDUMP_OBJECT (qtdemux, "hvc1", buffer, end - buffer);
5909 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
5914 GST_MEMDUMP_OBJECT (qtdemux, "hev1", buffer, end - buffer);
5915 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
5920 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
5925 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
5926 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
5931 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
5932 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
5933 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
5941 version = QT_UINT32 (buffer + 12);
5942 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
5949 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
5954 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
5959 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
5964 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
5968 if (!strcmp (type->name, "unknown"))
5969 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
5973 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
5974 GST_FOURCC_ARGS (fourcc));
5980 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5981 (_("This file is corrupt and cannot be played.")),
5982 ("Not enough data for an atom header, got only %u bytes", length));
5987 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5988 (_("This file is corrupt and cannot be played.")),
5989 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
5990 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
5997 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
6001 guint32 child_fourcc;
6003 for (child = g_node_first_child (node); child;
6004 child = g_node_next_sibling (child)) {
6005 buffer = (guint8 *) child->data;
6007 child_fourcc = QT_FOURCC (buffer + 4);
6009 if (G_UNLIKELY (child_fourcc == fourcc)) {
6017 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
6018 GstByteReader * parser)
6022 guint32 child_fourcc, child_len;
6024 for (child = g_node_first_child (node); child;
6025 child = g_node_next_sibling (child)) {
6026 buffer = (guint8 *) child->data;
6028 child_len = QT_UINT32 (buffer);
6029 child_fourcc = QT_FOURCC (buffer + 4);
6031 if (G_UNLIKELY (child_fourcc == fourcc)) {
6032 if (G_UNLIKELY (child_len < (4 + 4)))
6034 /* FIXME: must verify if atom length < parent atom length */
6035 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
6043 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
6044 GstByteReader * parser)
6048 guint32 child_fourcc, child_len;
6050 for (child = g_node_next_sibling (node); child;
6051 child = g_node_next_sibling (child)) {
6052 buffer = (guint8 *) child->data;
6054 child_fourcc = QT_FOURCC (buffer + 4);
6056 if (child_fourcc == fourcc) {
6058 child_len = QT_UINT32 (buffer);
6059 if (G_UNLIKELY (child_len < (4 + 4)))
6061 /* FIXME: must verify if atom length < parent atom length */
6062 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
6071 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
6073 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
6077 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
6079 /* FIXME: This can only reliably work if demuxers have a
6080 * separate streaming thread per srcpad. This should be
6081 * done in a demuxer base class, which integrates parts
6084 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
6089 query = gst_query_new_allocation (stream->caps, FALSE);
6091 if (!gst_pad_peer_query (stream->pad, query)) {
6092 /* not a problem, just debug a little */
6093 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
6096 if (stream->allocator)
6097 gst_object_unref (stream->allocator);
6099 if (gst_query_get_n_allocation_params (query) > 0) {
6100 /* try the allocator */
6101 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
6103 stream->use_allocator = TRUE;
6105 stream->allocator = NULL;
6106 gst_allocation_params_init (&stream->params);
6107 stream->use_allocator = FALSE;
6109 gst_query_unref (query);
6114 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
6116 if (stream->subtype == FOURCC_vide) {
6117 /* fps is calculated base on the duration of the average framerate since
6118 * qt does not have a fixed framerate. */
6119 if ((stream->n_samples == 1) && (stream->first_duration == 0)) {
6124 if (stream->duration == 0 || stream->n_samples < 2) {
6125 stream->fps_n = stream->timescale;
6128 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
6129 /* stream->duration is guint64, timescale, n_samples are guint32 */
6130 GstClockTime avg_duration =
6131 gst_util_uint64_scale_round (stream->duration -
6132 stream->first_duration, GST_SECOND,
6133 (guint64) (stream->timescale) * (stream->n_samples - 1));
6135 GST_LOG_OBJECT (qtdemux,
6136 "Calculating avg sample duration based on stream duration %"
6138 " minus first sample %u, leaving %d samples gives %"
6139 GST_TIME_FORMAT, stream->duration, stream->first_duration,
6140 stream->n_samples - 1, GST_TIME_ARGS (avg_duration));
6142 gst_video_guess_framerate (avg_duration, &stream->fps_n,
6145 GST_DEBUG_OBJECT (qtdemux,
6146 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
6147 stream->timescale, stream->fps_n, stream->fps_d);
6151 stream->caps = gst_caps_make_writable (stream->caps);
6153 gst_caps_set_simple (stream->caps,
6154 "width", G_TYPE_INT, stream->width,
6155 "height", G_TYPE_INT, stream->height,
6156 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
6158 /* calculate pixel-aspect-ratio using display width and height */
6159 GST_DEBUG_OBJECT (qtdemux,
6160 "video size %dx%d, target display size %dx%d", stream->width,
6161 stream->height, stream->display_width, stream->display_height);
6163 if (stream->display_width > 0 && stream->display_height > 0 &&
6164 stream->width > 0 && stream->height > 0) {
6167 /* calculate the pixel aspect ratio using the display and pixel w/h */
6168 n = stream->display_width * stream->height;
6169 d = stream->display_height * stream->width;
6172 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
6173 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
6174 GST_TYPE_FRACTION, n, d, NULL);
6177 /* qt file might have pasp atom */
6178 if (stream->par_w > 0 && stream->par_h > 0) {
6179 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
6180 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
6181 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
6184 } else if (stream->subtype == FOURCC_soun) {
6186 stream->caps = gst_caps_make_writable (stream->caps);
6187 if (stream->rate > 0)
6188 gst_caps_set_simple (stream->caps,
6189 "rate", G_TYPE_INT, (int) stream->rate, NULL);
6190 if (stream->n_channels > 0)
6191 gst_caps_set_simple (stream->caps,
6192 "channels", G_TYPE_INT, stream->n_channels, NULL);
6193 if (stream->n_channels > 2) {
6194 /* FIXME: Need to parse the 'chan' atom to get channel layouts
6195 * correctly; this is just the minimum we can do - assume
6196 * we don't actually have any channel positions. */
6197 gst_caps_set_simple (stream->caps,
6198 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
6204 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
6205 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
6206 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
6207 gst_pad_set_active (stream->pad, TRUE);
6209 gst_pad_use_fixed_caps (stream->pad);
6211 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
6212 if (stream->new_stream) {
6215 GstStreamFlags stream_flags;
6218 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
6221 if (gst_event_parse_group_id (event, &qtdemux->group_id))
6222 qtdemux->have_group_id = TRUE;
6224 qtdemux->have_group_id = FALSE;
6225 gst_event_unref (event);
6226 } else if (!qtdemux->have_group_id) {
6227 qtdemux->have_group_id = TRUE;
6228 qtdemux->group_id = gst_util_group_id_next ();
6231 stream->new_stream = FALSE;
6233 gst_pad_create_stream_id_printf (stream->pad,
6234 GST_ELEMENT_CAST (qtdemux), "%03u", stream->track_id);
6235 event = gst_event_new_stream_start (stream_id);
6236 if (qtdemux->have_group_id)
6237 gst_event_set_group_id (event, qtdemux->group_id);
6238 stream_flags = GST_STREAM_FLAG_NONE;
6239 if (stream->disabled)
6240 stream_flags |= GST_STREAM_FLAG_UNSELECT;
6242 stream_flags |= GST_STREAM_FLAG_SPARSE;
6243 gst_event_set_stream_flags (event, stream_flags);
6244 gst_pad_push_event (stream->pad, event);
6247 gst_pad_set_caps (stream->pad, stream->caps);
6248 stream->new_caps = FALSE;
6254 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
6255 QtDemuxStream * stream, GstTagList * list)
6257 /* consistent default for push based mode */
6258 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
6260 if (stream->subtype == FOURCC_vide) {
6261 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
6264 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
6267 gst_qtdemux_configure_stream (qtdemux, stream);
6268 qtdemux->n_video_streams++;
6269 } else if (stream->subtype == FOURCC_soun) {
6270 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
6273 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
6275 gst_qtdemux_configure_stream (qtdemux, stream);
6276 qtdemux->n_audio_streams++;
6277 } else if (stream->subtype == FOURCC_strm) {
6278 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
6279 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
6280 || stream->subtype == FOURCC_sbtl) {
6281 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
6284 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
6286 gst_qtdemux_configure_stream (qtdemux, stream);
6287 qtdemux->n_sub_streams++;
6288 } else if (stream->caps) {
6289 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
6292 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
6294 gst_qtdemux_configure_stream (qtdemux, stream);
6295 qtdemux->n_video_streams++;
6297 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
6302 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
6303 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
6304 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
6305 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
6307 if (stream->pending_tags)
6308 gst_tag_list_unref (stream->pending_tags);
6309 stream->pending_tags = list;
6310 /* global tags go on each pad anyway */
6311 stream->send_global_tags = TRUE;
6317 /* find next atom with @fourcc starting at @offset */
6318 static GstFlowReturn
6319 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
6320 guint64 * length, guint32 fourcc)
6326 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
6327 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
6333 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
6334 if (G_UNLIKELY (ret != GST_FLOW_OK))
6336 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
6339 gst_buffer_unref (buf);
6342 gst_buffer_map (buf, &map, GST_MAP_READ);
6343 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
6344 gst_buffer_unmap (buf, &map);
6345 gst_buffer_unref (buf);
6347 if (G_UNLIKELY (*length == 0)) {
6348 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
6349 ret = GST_FLOW_ERROR;
6353 if (lfourcc == fourcc) {
6354 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
6358 GST_LOG_OBJECT (qtdemux,
6359 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
6360 GST_FOURCC_ARGS (fourcc), *offset);
6369 /* might simply have had last one */
6370 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
6375 /* should only do something in pull mode */
6376 /* call with OBJECT lock */
6377 static GstFlowReturn
6378 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
6380 guint64 length, offset;
6381 GstBuffer *buf = NULL;
6382 GstFlowReturn ret = GST_FLOW_OK;
6383 GstFlowReturn res = GST_FLOW_OK;
6386 offset = qtdemux->moof_offset;
6387 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
6390 GST_DEBUG_OBJECT (qtdemux, "no next moof");
6391 return GST_FLOW_EOS;
6394 /* best not do pull etc with lock held */
6395 GST_OBJECT_UNLOCK (qtdemux);
6397 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
6398 if (ret != GST_FLOW_OK)
6401 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
6402 if (G_UNLIKELY (ret != GST_FLOW_OK))
6404 gst_buffer_map (buf, &map, GST_MAP_READ);
6405 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
6406 gst_buffer_unmap (buf, &map);
6407 gst_buffer_unref (buf);
6412 gst_buffer_unmap (buf, &map);
6413 gst_buffer_unref (buf);
6417 /* look for next moof */
6418 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
6419 if (G_UNLIKELY (ret != GST_FLOW_OK))
6423 GST_OBJECT_LOCK (qtdemux);
6425 qtdemux->moof_offset = offset;
6431 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
6433 res = GST_FLOW_ERROR;
6438 /* maybe upstream temporarily flushing */
6439 if (ret != GST_FLOW_FLUSHING) {
6440 GST_DEBUG_OBJECT (qtdemux, "no next moof");
6443 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
6444 /* resume at current position next time */
6451 /* initialise bytereaders for stbl sub-atoms */
6453 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
6455 stream->stbl_index = -1; /* no samples have yet been parsed */
6456 stream->sample_index = -1;
6458 /* time-to-sample atom */
6459 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
6462 /* copy atom data into a new buffer for later use */
6463 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
6465 /* skip version + flags */
6466 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
6467 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
6469 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
6471 /* make sure there's enough data */
6472 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
6473 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
6474 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
6475 stream->n_sample_times);
6476 if (!stream->n_sample_times)
6480 /* sync sample atom */
6481 stream->stps_present = FALSE;
6482 if ((stream->stss_present =
6483 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
6484 &stream->stss) ? TRUE : FALSE) == TRUE) {
6485 /* copy atom data into a new buffer for later use */
6486 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
6488 /* skip version + flags */
6489 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
6490 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
6493 if (stream->n_sample_syncs) {
6494 /* make sure there's enough data */
6495 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
6499 /* partial sync sample atom */
6500 if ((stream->stps_present =
6501 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
6502 &stream->stps) ? TRUE : FALSE) == TRUE) {
6503 /* copy atom data into a new buffer for later use */
6504 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
6506 /* skip version + flags */
6507 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
6508 !gst_byte_reader_get_uint32_be (&stream->stps,
6509 &stream->n_sample_partial_syncs))
6512 /* if there are no entries, the stss table contains the real
6514 if (stream->n_sample_partial_syncs) {
6515 /* make sure there's enough data */
6516 if (!qt_atom_parser_has_chunks (&stream->stps,
6517 stream->n_sample_partial_syncs, 4))
6524 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
6527 /* copy atom data into a new buffer for later use */
6528 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
6530 /* skip version + flags */
6531 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
6532 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
6535 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
6538 if (!stream->n_samples)
6541 /* sample-to-chunk atom */
6542 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
6545 /* copy atom data into a new buffer for later use */
6546 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
6548 /* skip version + flags */
6549 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
6550 !gst_byte_reader_get_uint32_be (&stream->stsc,
6551 &stream->n_samples_per_chunk))
6554 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
6555 stream->n_samples_per_chunk);
6557 /* make sure there's enough data */
6558 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
6564 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
6565 stream->co_size = sizeof (guint32);
6566 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
6568 stream->co_size = sizeof (guint64);
6572 /* copy atom data into a new buffer for later use */
6573 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
6575 /* skip version + flags */
6576 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
6579 /* chunks_are_samples == TRUE means treat chunks as samples */
6580 stream->chunks_are_samples = stream->sample_size && !stream->sampled;
6581 if (stream->chunks_are_samples) {
6582 /* treat chunks as samples */
6583 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
6586 /* skip number of entries */
6587 if (!gst_byte_reader_skip (&stream->stco, 4))
6590 /* make sure there are enough data in the stsz atom */
6591 if (!stream->sample_size) {
6592 /* different sizes for each sample */
6593 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
6598 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
6599 stream->n_samples, (guint) sizeof (QtDemuxSample),
6600 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
6602 if (stream->n_samples >=
6603 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
6604 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
6605 "be larger than %uMB (broken file?)", stream->n_samples,
6606 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
6610 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
6611 if (!stream->samples) {
6612 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
6618 /* composition time-to-sample */
6619 if ((stream->ctts_present =
6620 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
6621 &stream->ctts) ? TRUE : FALSE) == TRUE) {
6622 /* copy atom data into a new buffer for later use */
6623 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
6625 /* skip version + flags */
6626 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
6627 || !gst_byte_reader_get_uint32_be (&stream->ctts,
6628 &stream->n_composition_times))
6631 /* make sure there's enough data */
6632 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
6641 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
6642 (_("This file is corrupt and cannot be played.")), (NULL));
6647 gst_qtdemux_stbl_free (stream);
6648 if (!qtdemux->fragmented) {
6649 /* not quite good */
6650 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
6653 /* may pick up samples elsewhere */
6659 /* collect samples from the next sample to be parsed up to sample @n for @stream
6660 * by reading the info from @stbl
6662 * This code can be executed from both the streaming thread and the seeking
6663 * thread so it takes the object lock to protect itself
6666 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
6669 QtDemuxSample *samples, *first, *cur, *last;
6670 guint32 n_samples_per_chunk;
6673 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
6674 GST_FOURCC_FORMAT ", pad %s", GST_FOURCC_ARGS (stream->fourcc),
6675 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
6677 n_samples = stream->n_samples;
6680 goto out_of_samples;
6682 GST_OBJECT_LOCK (qtdemux);
6683 if (n <= stream->stbl_index)
6684 goto already_parsed;
6686 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
6688 if (!stream->stsz.data) {
6689 /* so we already parsed and passed all the moov samples;
6690 * onto fragmented ones */
6691 g_assert (qtdemux->fragmented);
6695 /* pointer to the sample table */
6696 samples = stream->samples;
6698 /* starts from -1, moves to the next sample index to parse */
6699 stream->stbl_index++;
6701 /* keep track of the first and last sample to fill */
6702 first = &samples[stream->stbl_index];
6705 if (!stream->chunks_are_samples) {
6706 /* set the sample sizes */
6707 if (stream->sample_size == 0) {
6708 /* different sizes for each sample */
6709 for (cur = first; cur <= last; cur++) {
6710 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
6711 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
6712 (guint) (cur - samples), cur->size);
6715 /* samples have the same size */
6716 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
6717 for (cur = first; cur <= last; cur++)
6718 cur->size = stream->sample_size;
6722 n_samples_per_chunk = stream->n_samples_per_chunk;
6725 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
6728 if (stream->stsc_chunk_index >= stream->last_chunk
6729 || stream->stsc_chunk_index < stream->first_chunk) {
6730 stream->first_chunk =
6731 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
6732 stream->samples_per_chunk =
6733 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
6734 gst_byte_reader_skip_unchecked (&stream->stsc, 4);
6736 /* chunk numbers are counted from 1 it seems */
6737 if (G_UNLIKELY (stream->first_chunk == 0))
6740 --stream->first_chunk;
6742 /* the last chunk of each entry is calculated by taking the first chunk
6743 * of the next entry; except if there is no next, where we fake it with
6745 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
6746 stream->last_chunk = G_MAXUINT32;
6748 stream->last_chunk =
6749 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
6750 if (G_UNLIKELY (stream->last_chunk == 0))
6753 --stream->last_chunk;
6756 GST_LOG_OBJECT (qtdemux,
6757 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
6758 stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
6760 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
6763 if (stream->last_chunk != G_MAXUINT32) {
6764 if (!qt_atom_parser_peek_sub (&stream->stco,
6765 stream->first_chunk * stream->co_size,
6766 (stream->last_chunk - stream->first_chunk) * stream->co_size,
6771 stream->co_chunk = stream->stco;
6772 if (!gst_byte_reader_skip (&stream->co_chunk,
6773 stream->first_chunk * stream->co_size))
6777 stream->stsc_chunk_index = stream->first_chunk;
6780 last_chunk = stream->last_chunk;
6782 if (stream->chunks_are_samples) {
6783 cur = &samples[stream->stsc_chunk_index];
6785 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
6788 stream->stsc_chunk_index = j;
6793 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
6796 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
6797 "%" G_GUINT64_FORMAT, j, cur->offset);
6799 if (stream->samples_per_frame * stream->bytes_per_frame) {
6801 (stream->samples_per_chunk * stream->n_channels) /
6802 stream->samples_per_frame * stream->bytes_per_frame;
6804 cur->size = stream->samples_per_chunk;
6807 GST_DEBUG_OBJECT (qtdemux,
6808 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
6809 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
6810 stream->stco_sample_index)), cur->size);
6812 cur->timestamp = stream->stco_sample_index;
6813 cur->duration = stream->samples_per_chunk;
6814 cur->keyframe = TRUE;
6817 stream->stco_sample_index += stream->samples_per_chunk;
6819 stream->stsc_chunk_index = j;
6821 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
6822 guint32 samples_per_chunk;
6823 guint64 chunk_offset;
6825 if (!stream->stsc_sample_index
6826 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
6827 &stream->chunk_offset))
6830 samples_per_chunk = stream->samples_per_chunk;
6831 chunk_offset = stream->chunk_offset;
6833 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
6834 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
6835 G_GUINT64_FORMAT " and size %d",
6836 (guint) (cur - samples), chunk_offset, cur->size);
6838 cur->offset = chunk_offset;
6839 chunk_offset += cur->size;
6842 if (G_UNLIKELY (cur > last)) {
6844 stream->stsc_sample_index = k + 1;
6845 stream->chunk_offset = chunk_offset;
6846 stream->stsc_chunk_index = j;
6850 stream->stsc_sample_index = 0;
6852 stream->stsc_chunk_index = j;
6854 stream->stsc_index++;
6857 if (stream->chunks_are_samples)
6861 guint32 n_sample_times;
6863 n_sample_times = stream->n_sample_times;
6866 for (i = stream->stts_index; i < n_sample_times; i++) {
6867 guint32 stts_samples;
6868 gint32 stts_duration;
6871 if (stream->stts_sample_index >= stream->stts_samples
6872 || !stream->stts_sample_index) {
6874 stream->stts_samples =
6875 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
6876 stream->stts_duration =
6877 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
6879 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
6880 i, stream->stts_samples, stream->stts_duration);
6882 stream->stts_sample_index = 0;
6885 stts_samples = stream->stts_samples;
6886 stts_duration = stream->stts_duration;
6887 stts_time = stream->stts_time;
6889 for (j = stream->stts_sample_index; j < stts_samples; j++) {
6890 GST_DEBUG_OBJECT (qtdemux,
6891 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
6892 (guint) (cur - samples), j,
6893 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
6895 cur->timestamp = stts_time;
6896 cur->duration = stts_duration;
6898 /* avoid 32-bit wrap-around,
6899 * but still mind possible 'negative' duration */
6900 stts_time += (gint64) stts_duration;
6903 if (G_UNLIKELY (cur > last)) {
6905 stream->stts_time = stts_time;
6906 stream->stts_sample_index = j + 1;
6910 stream->stts_sample_index = 0;
6911 stream->stts_time = stts_time;
6912 stream->stts_index++;
6914 /* fill up empty timestamps with the last timestamp, this can happen when
6915 * the last samples do not decode and so we don't have timestamps for them.
6916 * We however look at the last timestamp to estimate the track length so we
6917 * need something in here. */
6918 for (; cur < last; cur++) {
6919 GST_DEBUG_OBJECT (qtdemux,
6920 "fill sample %d: timestamp %" GST_TIME_FORMAT,
6921 (guint) (cur - samples),
6922 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
6923 cur->timestamp = stream->stts_time;
6929 /* sample sync, can be NULL */
6930 if (stream->stss_present == TRUE) {
6931 guint32 n_sample_syncs;
6933 n_sample_syncs = stream->n_sample_syncs;
6935 if (!n_sample_syncs) {
6936 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
6937 stream->all_keyframe = TRUE;
6939 for (i = stream->stss_index; i < n_sample_syncs; i++) {
6940 /* note that the first sample is index 1, not 0 */
6943 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
6945 if (G_LIKELY (index > 0 && index <= n_samples)) {
6947 samples[index].keyframe = TRUE;
6948 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
6949 /* and exit if we have enough samples */
6950 if (G_UNLIKELY (index >= n)) {
6957 stream->stss_index = i;
6960 /* stps marks partial sync frames like open GOP I-Frames */
6961 if (stream->stps_present == TRUE) {
6962 guint32 n_sample_partial_syncs;
6964 n_sample_partial_syncs = stream->n_sample_partial_syncs;
6966 /* if there are no entries, the stss table contains the real
6968 if (n_sample_partial_syncs) {
6969 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
6970 /* note that the first sample is index 1, not 0 */
6973 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
6975 if (G_LIKELY (index > 0 && index <= n_samples)) {
6977 samples[index].keyframe = TRUE;
6978 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
6979 /* and exit if we have enough samples */
6980 if (G_UNLIKELY (index >= n)) {
6987 stream->stps_index = i;
6991 /* no stss, all samples are keyframes */
6992 stream->all_keyframe = TRUE;
6993 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
6998 /* composition time to sample */
6999 if (stream->ctts_present == TRUE) {
7000 guint32 n_composition_times;
7002 gint32 ctts_soffset;
7004 /* Fill in the pts_offsets */
7006 n_composition_times = stream->n_composition_times;
7008 for (i = stream->ctts_index; i < n_composition_times; i++) {
7009 if (stream->ctts_sample_index >= stream->ctts_count
7010 || !stream->ctts_sample_index) {
7011 stream->ctts_count =
7012 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
7013 stream->ctts_soffset =
7014 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
7015 stream->ctts_sample_index = 0;
7018 ctts_count = stream->ctts_count;
7019 ctts_soffset = stream->ctts_soffset;
7021 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
7022 cur->pts_offset = ctts_soffset;
7025 if (G_UNLIKELY (cur > last)) {
7027 stream->ctts_sample_index = j + 1;
7031 stream->ctts_sample_index = 0;
7032 stream->ctts_index++;
7036 stream->stbl_index = n;
7037 /* if index has been completely parsed, free data that is no-longer needed */
7038 if (n + 1 == stream->n_samples) {
7039 gst_qtdemux_stbl_free (stream);
7040 GST_DEBUG_OBJECT (qtdemux,
7041 "parsed all available samples; checking for more");
7042 while (n + 1 == stream->n_samples)
7043 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
7046 GST_OBJECT_UNLOCK (qtdemux);
7053 GST_LOG_OBJECT (qtdemux,
7054 "Tried to parse up to sample %u but this sample has already been parsed",
7056 /* if fragmented, there may be more */
7057 if (qtdemux->fragmented && n == stream->stbl_index)
7059 GST_OBJECT_UNLOCK (qtdemux);
7065 GST_LOG_OBJECT (qtdemux,
7066 "Tried to parse up to sample %u but there are only %u samples", n + 1,
7068 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7069 (_("This file is corrupt and cannot be played.")), (NULL));
7074 GST_OBJECT_UNLOCK (qtdemux);
7075 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7076 (_("This file is corrupt and cannot be played.")), (NULL));
7081 /* collect all segment info for @stream.
7084 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
7089 /* parse and prepare segment info from the edit list */
7090 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
7091 stream->n_segments = 0;
7092 stream->segments = NULL;
7093 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
7101 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
7102 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
7105 buffer = elst->data;
7107 n_segments = QT_UINT32 (buffer + 12);
7109 /* we might allocate a bit too much, at least allocate 1 segment */
7110 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
7112 /* segments always start from 0 */
7116 for (i = 0; i < n_segments; i++) {
7119 QtDemuxSegment *segment;
7122 media_time = QT_UINT32 (buffer + 20 + i * 12);
7123 duration = QT_UINT32 (buffer + 16 + i * 12);
7125 segment = &stream->segments[count++];
7127 /* time and duration expressed in global timescale */
7128 segment->time = stime;
7129 /* add non scaled values so we don't cause roundoff errors */
7131 stime = QTTIME_TO_GSTTIME (qtdemux, time);
7132 segment->stop_time = stime;
7133 segment->duration = stime - segment->time;
7135 segment->trak_media_start = media_time;
7136 /* media_time expressed in stream timescale */
7137 if (media_time != G_MAXUINT32) {
7138 segment->media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
7139 segment->media_stop = segment->media_start + segment->duration;
7141 segment->media_start = GST_CLOCK_TIME_NONE;
7142 segment->media_stop = GST_CLOCK_TIME_NONE;
7144 rate_int = GST_READ_UINT32_BE (buffer + 24 + i * 12);
7146 if (rate_int <= 1) {
7147 /* 0 is not allowed, some programs write 1 instead of the floating point
7149 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
7153 segment->rate = rate_int / 65536.0;
7156 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
7157 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
7158 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
7159 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
7160 i, GST_TIME_ARGS (segment->time),
7161 GST_TIME_ARGS (segment->duration),
7162 GST_TIME_ARGS (segment->media_start), media_time,
7163 GST_TIME_ARGS (segment->media_stop),
7164 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
7166 if (segment->stop_time > qtdemux->segment.stop) {
7167 GST_WARNING_OBJECT (qtdemux, "Segment %d "
7168 " extends to %" GST_TIME_FORMAT
7169 " past the end of the file duration %" GST_TIME_FORMAT
7170 " it will be truncated", i, GST_TIME_ARGS (segment->stop_time),
7171 GST_TIME_ARGS (qtdemux->segment.stop));
7172 qtdemux->segment.stop = segment->stop_time;
7175 GST_DEBUG_OBJECT (qtdemux, "found %d segments", count);
7176 stream->n_segments = count;
7180 /* push based does not handle segments, so act accordingly here,
7181 * and warn if applicable */
7182 if (!qtdemux->pullbased) {
7183 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
7184 /* remove and use default one below, we stream like it anyway */
7185 g_free (stream->segments);
7186 stream->segments = NULL;
7187 stream->n_segments = 0;
7190 /* no segments, create one to play the complete trak */
7191 if (stream->n_segments == 0) {
7192 GstClockTime stream_duration =
7193 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
7195 if (stream->segments == NULL)
7196 stream->segments = g_new (QtDemuxSegment, 1);
7198 /* represent unknown our way */
7199 if (stream_duration == 0)
7200 stream_duration = GST_CLOCK_TIME_NONE;
7202 stream->segments[0].time = 0;
7203 stream->segments[0].stop_time = stream_duration;
7204 stream->segments[0].duration = stream_duration;
7205 stream->segments[0].media_start = 0;
7206 stream->segments[0].media_stop = stream_duration;
7207 stream->segments[0].rate = 1.0;
7208 stream->segments[0].trak_media_start = 0;
7210 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
7211 GST_TIME_ARGS (stream_duration));
7212 stream->n_segments = 1;
7213 stream->dummy_segment = TRUE;
7215 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
7221 * Parses the stsd atom of a svq3 trak looking for
7222 * the SMI and gama atoms.
7225 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
7226 guint8 ** gamma, GstBuffer ** seqh)
7228 guint8 *_gamma = NULL;
7229 GstBuffer *_seqh = NULL;
7230 guint8 *stsd_data = stsd->data;
7231 guint32 length = QT_UINT32 (stsd_data);
7235 GST_WARNING_OBJECT (qtdemux, "stsd too short");
7241 version = QT_UINT16 (stsd_data);
7246 while (length > 8) {
7247 guint32 fourcc, size;
7249 size = QT_UINT32 (stsd_data);
7250 fourcc = QT_FOURCC (stsd_data + 4);
7251 data = stsd_data + 8;
7254 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
7255 "svq3 atom parsing");
7264 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
7265 " for gama atom, expected 12", size);
7270 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
7272 if (_seqh != NULL) {
7273 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
7274 " found, ignoring");
7276 seqh_size = QT_UINT32 (data + 4);
7277 if (seqh_size > 0) {
7278 _seqh = gst_buffer_new_and_alloc (seqh_size);
7279 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
7286 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
7287 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
7291 if (size <= length) {
7297 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
7300 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
7301 G_GUINT16_FORMAT, version);
7312 gst_buffer_unref (_seqh);
7317 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
7324 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
7325 * atom that might contain a 'data' atom with the rtsp uri.
7326 * This case was reported in bug #597497, some info about
7327 * the hndl atom can be found in TN1195
7329 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
7330 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
7333 guint32 dref_num_entries = 0;
7334 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
7335 gst_byte_reader_skip (&dref, 4) &&
7336 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
7339 /* search dref entries for hndl atom */
7340 for (i = 0; i < dref_num_entries; i++) {
7341 guint32 size = 0, type;
7342 guint8 string_len = 0;
7343 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
7344 qt_atom_parser_get_fourcc (&dref, &type)) {
7345 if (type == FOURCC_hndl) {
7346 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
7348 /* skip data reference handle bytes and the
7349 * following pascal string and some extra 4
7350 * bytes I have no idea what are */
7351 if (!gst_byte_reader_skip (&dref, 4) ||
7352 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
7353 !gst_byte_reader_skip (&dref, string_len + 4)) {
7354 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
7358 /* iterate over the atoms to find the data atom */
7359 while (gst_byte_reader_get_remaining (&dref) >= 8) {
7363 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
7364 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
7365 if (atom_type == FOURCC_data) {
7366 const guint8 *uri_aux = NULL;
7368 /* found the data atom that might contain the rtsp uri */
7369 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
7370 "hndl atom, interpreting it as an URI");
7371 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
7373 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
7374 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
7376 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
7377 "didn't contain a rtsp address");
7379 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
7384 /* skipping to the next entry */
7385 if (!gst_byte_reader_skip (&dref, atom_size - 8))
7388 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
7395 /* skip to the next entry */
7396 if (!gst_byte_reader_skip (&dref, size - 8))
7399 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
7402 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
7408 #define AMR_NB_ALL_MODES 0x81ff
7409 #define AMR_WB_ALL_MODES 0x83ff
7411 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
7413 /* The 'damr' atom is of the form:
7415 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
7416 * 32 b 8 b 16 b 8 b 8 b
7418 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
7419 * represents the highest mode used in the stream (and thus the maximum
7420 * bitrate), with a couple of special cases as seen below.
7423 /* Map of frame type ID -> bitrate */
7424 static const guint nb_bitrates[] = {
7425 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
7427 static const guint wb_bitrates[] = {
7428 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
7434 gst_buffer_map (buf, &map, GST_MAP_READ);
7436 if (map.size != 0x11) {
7437 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
7441 if (QT_FOURCC (map.data + 4) != GST_MAKE_FOURCC ('d', 'a', 'm', 'r')) {
7442 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
7443 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
7447 mode_set = QT_UINT16 (map.data + 13);
7449 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
7450 max_mode = 7 + (wb ? 1 : 0);
7452 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
7453 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
7455 if (max_mode == -1) {
7456 GST_DEBUG ("No mode indication was found (mode set) = %x",
7461 gst_buffer_unmap (buf, &map);
7462 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
7465 gst_buffer_unmap (buf, &map);
7470 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
7471 GstByteReader * reader, guint32 * matrix, const gchar * atom)
7474 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
7480 if (gst_byte_reader_get_remaining (reader) < 36)
7483 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
7484 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
7485 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
7486 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
7487 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
7488 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
7489 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
7490 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
7491 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
7493 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
7494 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
7495 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
7497 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
7498 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
7500 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
7501 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
7508 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
7509 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
7516 * This macro will only compare value abdegh, it expects cfi to have already
7519 #define QTCHECK_MATRIX(m,a,b,d,e,g,h) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
7520 (m)[3] == (d << 16) && (m)[4] == (e << 16) && \
7521 (m)[6] == (g << 16) && (m)[7] == (h << 16))
7523 /* only handle the cases where the last column has standard values */
7524 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
7525 const gchar *rotation_tag = NULL;
7527 /* no rotation needed */
7528 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1, 0, 0)) {
7530 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0,
7531 stream->display_height, 0)) {
7532 rotation_tag = "rotate-90";
7533 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16,
7534 stream->display_width, stream->display_height)) {
7535 rotation_tag = "rotate-180";
7536 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0, 0,
7537 stream->display_width)) {
7538 rotation_tag = "rotate-270";
7540 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
7543 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
7545 if (rotation_tag != NULL) {
7546 if (*taglist == NULL)
7547 *taglist = gst_tag_list_new_empty ();
7548 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
7549 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
7552 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
7557 * With each track we associate a new QtDemuxStream that contains all the info
7559 * traks that do not decode to something (like strm traks) will not have a pad.
7562 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
7579 QtDemuxStream *stream = NULL;
7580 gboolean new_stream = FALSE;
7581 GstTagList *list = NULL;
7582 gchar *codec = NULL;
7583 const guint8 *stsd_data;
7584 guint16 lang_code; /* quicktime lang code or packed iso code */
7586 guint32 tkhd_flags = 0;
7587 guint8 tkhd_version = 0;
7589 guint value_size, stsd_len, len;
7592 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
7594 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
7595 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
7596 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
7599 /* pick between 64 or 32 bits */
7600 value_size = tkhd_version == 1 ? 8 : 4;
7601 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
7602 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
7605 if (!qtdemux->got_moov) {
7606 if (qtdemux_find_stream (qtdemux, track_id))
7607 goto existing_stream;
7608 stream = _create_stream ();
7609 stream->track_id = track_id;
7612 stream = qtdemux_find_stream (qtdemux, track_id);
7614 GST_WARNING_OBJECT (qtdemux, "Stream not found, going to ignore it");
7619 if ((tkhd_flags & 1) == 0)
7620 stream->disabled = TRUE;
7622 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
7623 tkhd_version, tkhd_flags, stream->track_id);
7625 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
7628 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
7629 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
7630 if (qtdemux->major_brand != FOURCC_mjp2 ||
7631 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
7635 len = QT_UINT32 ((guint8 *) mdhd->data);
7636 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
7637 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
7638 if (version == 0x01000000) {
7641 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
7642 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
7643 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
7647 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
7648 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
7649 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
7652 if (lang_code < 0x400) {
7653 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
7654 } else if (lang_code == 0x7fff) {
7655 stream->lang_id[0] = 0; /* unspecified */
7657 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
7658 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
7659 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
7660 stream->lang_id[3] = 0;
7663 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
7665 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
7667 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
7668 lang_code, stream->lang_id);
7670 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
7673 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
7674 /* chapters track reference */
7675 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
7677 gsize length = GST_READ_UINT32_BE (chap->data);
7678 if (qtdemux->chapters_track_id)
7679 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
7682 qtdemux->chapters_track_id =
7683 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
7688 /* fragmented files may have bogus duration in moov */
7689 if (!qtdemux->fragmented &&
7690 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
7691 guint64 tdur1, tdur2;
7693 /* don't overflow */
7694 tdur1 = stream->timescale * (guint64) qtdemux->duration;
7695 tdur2 = qtdemux->timescale * (guint64) stream->duration;
7698 * some of those trailers, nowadays, have prologue images that are
7699 * themselves vide tracks as well. I haven't really found a way to
7700 * identify those yet, except for just looking at their duration. */
7701 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
7702 GST_WARNING_OBJECT (qtdemux,
7703 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
7704 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
7705 "found, assuming preview image or something; skipping track",
7706 stream->duration, stream->timescale, qtdemux->duration,
7707 qtdemux->timescale);
7713 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
7716 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
7717 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
7719 len = QT_UINT32 ((guint8 *) hdlr->data);
7721 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
7722 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
7723 GST_FOURCC_ARGS (stream->subtype));
7725 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
7728 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
7732 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
7734 stsd_data = (const guint8 *) stsd->data;
7736 /* stsd should at least have one entry */
7737 stsd_len = QT_UINT32 (stsd_data);
7738 if (stsd_len < 24) {
7739 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
7740 if (stream->subtype == FOURCC_vivo) {
7748 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
7750 /* and that entry should fit within stsd */
7751 len = QT_UINT32 (stsd_data + 16);
7752 if (len > stsd_len + 16)
7755 stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
7756 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
7757 GST_FOURCC_ARGS (stream->fourcc));
7758 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
7760 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi) ||
7761 ((fourcc & 0x00FFFFFF) == GST_MAKE_FOURCC ('e', 'n', 'c', 0)))
7762 goto error_encrypted;
7764 if (stream->subtype == FOURCC_vide) {
7765 guint32 w = 0, h = 0;
7767 gint depth, palette_size, palette_count;
7769 guint32 *palette_data = NULL;
7771 stream->sampled = TRUE;
7773 /* version 1 uses some 64-bit ints */
7774 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
7777 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
7780 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
7781 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
7784 stream->display_width = w >> 16;
7785 stream->display_height = h >> 16;
7787 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix, &list);
7793 stream->width = QT_UINT16 (stsd_data + offset + 32);
7794 stream->height = QT_UINT16 (stsd_data + offset + 34);
7795 stream->fps_n = 0; /* this is filled in later */
7796 stream->fps_d = 0; /* this is filled in later */
7797 stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
7798 stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
7800 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
7801 stream->width, stream->height, stream->bits_per_sample,
7802 stream->color_table_id);
7804 depth = stream->bits_per_sample;
7806 /* more than 32 bits means grayscale */
7807 gray = (depth > 32);
7808 /* low 32 bits specify the depth */
7811 /* different number of palette entries is determined by depth. */
7813 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
7814 palette_count = (1 << depth);
7815 palette_size = palette_count * 4;
7817 if (stream->color_table_id) {
7818 switch (palette_count) {
7822 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
7825 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
7829 palette_data = g_memdup (ff_qt_grayscale_palette_16, palette_size);
7831 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
7835 palette_data = g_memdup (ff_qt_grayscale_palette_256, palette_size);
7837 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
7840 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
7841 (_("The video in this file might not play correctly.")),
7842 ("unsupported palette depth %d", depth));
7846 gint i, j, start, end;
7852 start = QT_UINT32 (stsd_data + offset + 86);
7853 palette_count = QT_UINT16 (stsd_data + offset + 90);
7854 end = QT_UINT16 (stsd_data + offset + 92);
7856 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
7857 start, end, palette_count);
7864 if (len < 94 + (end - start) * 8)
7867 /* palette is always the same size */
7868 palette_data = g_malloc0 (256 * 4);
7869 palette_size = 256 * 4;
7871 for (j = 0, i = start; i <= end; j++, i++) {
7874 a = QT_UINT16 (stsd_data + offset + 94 + (j * 8));
7875 r = QT_UINT16 (stsd_data + offset + 96 + (j * 8));
7876 g = QT_UINT16 (stsd_data + offset + 98 + (j * 8));
7877 b = QT_UINT16 (stsd_data + offset + 100 + (j * 8));
7879 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
7880 (g & 0xff00) | (b >> 8);
7885 qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
7886 if (G_UNLIKELY (!stream->caps)) {
7887 g_free (palette_data);
7888 goto unknown_stream;
7893 list = gst_tag_list_new_empty ();
7894 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7895 GST_TAG_VIDEO_CODEC, codec, NULL);
7904 if (stream->rgb8_palette)
7905 gst_memory_unref (stream->rgb8_palette);
7906 stream->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
7907 palette_data, palette_size, 0, palette_size, palette_data, g_free);
7909 s = gst_caps_get_structure (stream->caps, 0);
7911 /* non-raw video has a palette_data property. raw video has the palette as
7912 * an extra plane that we append to the output buffers before we push
7914 if (!gst_structure_has_name (s, "video/x-raw")) {
7917 palette = gst_buffer_new ();
7918 gst_buffer_append_memory (palette, stream->rgb8_palette);
7919 stream->rgb8_palette = NULL;
7921 gst_caps_set_simple (stream->caps, "palette_data",
7922 GST_TYPE_BUFFER, palette, NULL);
7923 gst_buffer_unref (palette);
7925 } else if (palette_count != 0) {
7926 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
7927 (NULL), ("Unsupported palette depth %d", depth));
7930 GST_LOG_OBJECT (qtdemux, "frame count: %u",
7931 QT_UINT16 (stsd_data + offset + 48));
7935 /* pick 'the' stsd child */
7936 mp4v = qtdemux_tree_get_child_by_type (stsd, fourcc);
7938 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
7939 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
7943 const guint8 *pasp_data = (const guint8 *) pasp->data;
7945 stream->par_w = QT_UINT32 (pasp_data + 8);
7946 stream->par_h = QT_UINT32 (pasp_data + 12);
7953 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
7960 gint len = QT_UINT32 (stsd_data) - 0x66;
7961 const guint8 *avc_data = stsd_data + 0x66;
7964 while (len >= 0x8) {
7967 if (QT_UINT32 (avc_data) <= len)
7968 size = QT_UINT32 (avc_data) - 0x8;
7973 /* No real data, so break out */
7976 switch (QT_FOURCC (avc_data + 0x4)) {
7979 /* parse, if found */
7982 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
7984 /* First 4 bytes are the length of the atom, the next 4 bytes
7985 * are the fourcc, the next 1 byte is the version, and the
7986 * subsequent bytes are profile_tier_level structure like data. */
7987 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
7988 avc_data + 8 + 1, size - 1);
7989 buf = gst_buffer_new_and_alloc (size);
7990 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
7991 gst_caps_set_simple (stream->caps,
7992 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7993 gst_buffer_unref (buf);
8001 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
8003 /* First 4 bytes are the length of the atom, the next 4 bytes
8004 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
8005 * next 1 byte is the version, and the
8006 * subsequent bytes are sequence parameter set like data. */
8008 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
8010 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
8011 avc_data + 8 + 40 + 1, size - 1);
8013 buf = gst_buffer_new_and_alloc (size);
8014 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
8015 gst_caps_set_simple (stream->caps,
8016 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8017 gst_buffer_unref (buf);
8023 guint avg_bitrate, max_bitrate;
8025 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
8029 max_bitrate = QT_UINT32 (avc_data + 0xc);
8030 avg_bitrate = QT_UINT32 (avc_data + 0x10);
8032 if (!max_bitrate && !avg_bitrate)
8035 /* Some muxers seem to swap the average and maximum bitrates
8036 * (I'm looking at you, YouTube), so we swap for sanity. */
8037 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
8038 guint temp = avg_bitrate;
8040 avg_bitrate = max_bitrate;
8045 list = gst_tag_list_new_empty ();
8047 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
8048 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
8049 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
8051 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
8052 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
8053 GST_TAG_BITRATE, avg_bitrate, NULL);
8064 avc_data += size + 8;
8073 gint len = QT_UINT32 (stsd_data) - 0x66;
8074 const guint8 *hevc_data = stsd_data + 0x66;
8077 while (len >= 0x8) {
8080 if (QT_UINT32 (hevc_data) <= len)
8081 size = QT_UINT32 (hevc_data) - 0x8;
8086 /* No real data, so break out */
8089 switch (QT_FOURCC (hevc_data + 0x4)) {
8092 /* parse, if found */
8095 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
8097 /* First 4 bytes are the length of the atom, the next 4 bytes
8098 * are the fourcc, the next 1 byte is the version, and the
8099 * subsequent bytes are sequence parameter set like data. */
8100 gst_codec_utils_h265_caps_set_level_tier_and_profile
8101 (stream->caps, hevc_data + 8 + 1, size - 1);
8103 buf = gst_buffer_new_and_alloc (size);
8104 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
8105 gst_caps_set_simple (stream->caps,
8106 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8107 gst_buffer_unref (buf);
8114 hevc_data += size + 8;
8125 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
8126 GST_FOURCC_ARGS (fourcc));
8128 /* codec data might be in glbl extension atom */
8130 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
8136 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
8138 len = QT_UINT32 (data);
8141 buf = gst_buffer_new_and_alloc (len);
8142 gst_buffer_fill (buf, 0, data + 8, len);
8143 gst_caps_set_simple (stream->caps,
8144 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8145 gst_buffer_unref (buf);
8152 /* see annex I of the jpeg2000 spec */
8153 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
8155 const gchar *colorspace = NULL;
8157 guint32 ncomp_map = 0;
8158 gint32 *comp_map = NULL;
8159 guint32 nchan_def = 0;
8160 gint32 *chan_def = NULL;
8162 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
8163 /* some required atoms */
8164 mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
8167 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
8171 /* number of components; redundant with info in codestream, but useful
8173 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
8174 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
8176 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
8178 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
8181 GST_DEBUG_OBJECT (qtdemux, "found colr");
8182 /* extract colour space info */
8183 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
8184 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
8186 colorspace = "sRGB";
8189 colorspace = "GRAY";
8192 colorspace = "sYUV";
8200 /* colr is required, and only values 16, 17, and 18 are specified,
8201 so error if we have no colorspace */
8204 /* extract component mapping */
8205 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
8207 guint32 cmap_len = 0;
8209 cmap_len = QT_UINT32 (cmap->data);
8210 if (cmap_len >= 8) {
8211 /* normal box, subtract off header */
8213 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
8214 if (cmap_len % 4 == 0) {
8215 ncomp_map = (cmap_len / 4);
8216 comp_map = g_new0 (gint32, ncomp_map);
8217 for (i = 0; i < ncomp_map; i++) {
8220 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
8221 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
8222 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
8223 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
8228 /* extract channel definitions */
8229 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
8231 guint32 cdef_len = 0;
8233 cdef_len = QT_UINT32 (cdef->data);
8234 if (cdef_len >= 10) {
8235 /* normal box, subtract off header and len */
8237 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
8238 if (cdef_len % 6 == 0) {
8239 nchan_def = (cdef_len / 6);
8240 chan_def = g_new0 (gint32, nchan_def);
8241 for (i = 0; i < nchan_def; i++)
8243 for (i = 0; i < nchan_def; i++) {
8244 guint16 cn, typ, asoc;
8245 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
8246 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
8247 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
8248 if (cn < nchan_def) {
8251 chan_def[cn] = asoc;
8254 chan_def[cn] = 0; /* alpha */
8257 chan_def[cn] = -typ;
8265 gst_caps_set_simple (stream->caps,
8266 "num-components", G_TYPE_INT, ncomp, NULL);
8267 gst_caps_set_simple (stream->caps,
8268 "colorspace", G_TYPE_STRING, colorspace, NULL);
8271 GValue arr = { 0, };
8272 GValue elt = { 0, };
8274 g_value_init (&arr, GST_TYPE_ARRAY);
8275 g_value_init (&elt, G_TYPE_INT);
8276 for (i = 0; i < ncomp_map; i++) {
8277 g_value_set_int (&elt, comp_map[i]);
8278 gst_value_array_append_value (&arr, &elt);
8280 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
8281 "component-map", &arr);
8282 g_value_unset (&elt);
8283 g_value_unset (&arr);
8288 GValue arr = { 0, };
8289 GValue elt = { 0, };
8291 g_value_init (&arr, GST_TYPE_ARRAY);
8292 g_value_init (&elt, G_TYPE_INT);
8293 for (i = 0; i < nchan_def; i++) {
8294 g_value_set_int (&elt, chan_def[i]);
8295 gst_value_array_append_value (&arr, &elt);
8297 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
8298 "channel-definitions", &arr);
8299 g_value_unset (&elt);
8300 g_value_unset (&arr);
8304 /* some optional atoms */
8305 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
8306 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
8308 /* indicate possible fields in caps */
8310 data = (guint8 *) field->data + 8;
8312 gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
8313 (gint) * data, NULL);
8315 /* add codec_data if provided */
8320 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
8321 data = prefix->data;
8322 len = QT_UINT32 (data);
8325 buf = gst_buffer_new_and_alloc (len);
8326 gst_buffer_fill (buf, 0, data + 8, len);
8327 gst_caps_set_simple (stream->caps,
8328 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8329 gst_buffer_unref (buf);
8338 GstBuffer *seqh = NULL;
8339 guint8 *gamma_data = NULL;
8340 gint len = QT_UINT32 (stsd_data);
8342 qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
8344 gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
8345 QT_FP32 (gamma_data), NULL);
8348 /* sorry for the bad name, but we don't know what this is, other
8349 * than its own fourcc */
8350 gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
8354 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
8355 buf = gst_buffer_new_and_alloc (len);
8356 gst_buffer_fill (buf, 0, stsd_data, len);
8357 gst_caps_set_simple (stream->caps,
8358 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8359 gst_buffer_unref (buf);
8365 gst_caps_set_simple (stream->caps,
8366 "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
8373 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
8374 xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
8378 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
8382 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
8383 /* collect the headers and store them in a stream list so that we can
8384 * send them out first */
8385 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
8395 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
8396 ovc1 = qtdemux_tree_get_child_by_type (stsd, FOURCC_ovc1);
8399 ovc1_data = ovc1->data;
8400 ovc1_len = QT_UINT32 (ovc1_data);
8401 if (ovc1_len <= 198) {
8402 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
8405 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
8406 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
8407 gst_caps_set_simple (stream->caps,
8408 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8409 gst_buffer_unref (buf);
8412 case GST_MAKE_FOURCC ('v', 'c', '-', '1'):
8414 gint len = QT_UINT32 (stsd_data) - 0x66;
8415 const guint8 *vc1_data = stsd_data + 0x66;
8421 if (QT_UINT32 (vc1_data) <= len)
8422 size = QT_UINT32 (vc1_data) - 8;
8427 /* No real data, so break out */
8430 switch (QT_FOURCC (vc1_data + 0x4)) {
8431 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
8435 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
8436 buf = gst_buffer_new_and_alloc (size);
8437 gst_buffer_fill (buf, 0, vc1_data + 8, size);
8438 gst_caps_set_simple (stream->caps,
8439 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8440 gst_buffer_unref (buf);
8447 vc1_data += size + 8;
8456 GST_INFO_OBJECT (qtdemux,
8457 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
8458 GST_FOURCC_ARGS (fourcc), stream->caps);
8460 } else if (stream->subtype == FOURCC_soun) {
8461 int version, samplesize;
8462 guint16 compression_id;
8463 gboolean amrwb = FALSE;
8466 /* sample description entry (16) + sound sample description v0 (20) */
8470 version = QT_UINT32 (stsd_data + offset);
8471 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
8472 samplesize = QT_UINT16 (stsd_data + offset + 10);
8473 compression_id = QT_UINT16 (stsd_data + offset + 12);
8474 stream->rate = QT_FP32 (stsd_data + offset + 16);
8476 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
8477 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
8478 QT_UINT32 (stsd_data + offset + 4));
8479 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
8480 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
8481 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
8482 GST_LOG_OBJECT (qtdemux, "packet size: %d",
8483 QT_UINT16 (stsd_data + offset + 14));
8484 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
8486 if (compression_id == 0xfffe)
8487 stream->sampled = TRUE;
8489 /* first assume uncompressed audio */
8490 stream->bytes_per_sample = samplesize / 8;
8491 stream->samples_per_frame = stream->n_channels;
8492 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
8493 stream->samples_per_packet = stream->samples_per_frame;
8494 stream->bytes_per_packet = stream->bytes_per_sample;
8498 /* Yes, these have to be hard-coded */
8501 stream->samples_per_packet = 6;
8502 stream->bytes_per_packet = 1;
8503 stream->bytes_per_frame = 1 * stream->n_channels;
8504 stream->bytes_per_sample = 1;
8505 stream->samples_per_frame = 6 * stream->n_channels;
8510 stream->samples_per_packet = 3;
8511 stream->bytes_per_packet = 1;
8512 stream->bytes_per_frame = 1 * stream->n_channels;
8513 stream->bytes_per_sample = 1;
8514 stream->samples_per_frame = 3 * stream->n_channels;
8519 stream->samples_per_packet = 64;
8520 stream->bytes_per_packet = 34;
8521 stream->bytes_per_frame = 34 * stream->n_channels;
8522 stream->bytes_per_sample = 2;
8523 stream->samples_per_frame = 64 * stream->n_channels;
8529 stream->samples_per_packet = 1;
8530 stream->bytes_per_packet = 1;
8531 stream->bytes_per_frame = 1 * stream->n_channels;
8532 stream->bytes_per_sample = 1;
8533 stream->samples_per_frame = 1 * stream->n_channels;
8538 stream->samples_per_packet = 160;
8539 stream->bytes_per_packet = 33;
8540 stream->bytes_per_frame = 33 * stream->n_channels;
8541 stream->bytes_per_sample = 2;
8542 stream->samples_per_frame = 160 * stream->n_channels;
8549 if (version == 0x00010000) {
8550 /* sample description entry (16) + sound sample description v1 (20+16) */
8561 /* only parse extra decoding config for non-pcm audio */
8562 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
8563 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
8564 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
8565 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
8567 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
8568 stream->samples_per_packet);
8569 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
8570 stream->bytes_per_packet);
8571 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
8572 stream->bytes_per_frame);
8573 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
8574 stream->bytes_per_sample);
8576 if (!stream->sampled && stream->bytes_per_packet) {
8577 stream->samples_per_frame = (stream->bytes_per_frame /
8578 stream->bytes_per_packet) * stream->samples_per_packet;
8579 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
8580 stream->samples_per_frame);
8585 } else if (version == 0x00020000) {
8592 /* sample description entry (16) + sound sample description v2 (56) */
8596 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
8597 stream->rate = qtfp.fp;
8598 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
8600 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
8601 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
8602 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
8603 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
8604 QT_UINT32 (stsd_data + offset + 20));
8605 GST_LOG_OBJECT (qtdemux, "format flags: %X",
8606 QT_UINT32 (stsd_data + offset + 24));
8607 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
8608 QT_UINT32 (stsd_data + offset + 28));
8609 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
8610 QT_UINT32 (stsd_data + offset + 32));
8611 } else if (version != 0x00000) {
8612 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x", version);
8615 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc,
8616 stsd_data + 32, len - 16, &codec);
8624 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
8626 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
8628 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
8630 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
8633 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
8634 gst_caps_set_simple (stream->caps,
8635 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE", NULL);
8642 const guint8 *owma_data;
8643 const gchar *codec_name = NULL;
8647 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
8648 /* FIXME this should also be gst_riff_strf_auds,
8649 * but the latter one is actually missing bits-per-sample :( */
8654 gint32 nSamplesPerSec;
8655 gint32 nAvgBytesPerSec;
8657 gint16 wBitsPerSample;
8662 GST_DEBUG_OBJECT (qtdemux, "parse owma");
8663 owma = qtdemux_tree_get_child_by_type (stsd, FOURCC_owma);
8666 owma_data = owma->data;
8667 owma_len = QT_UINT32 (owma_data);
8668 if (owma_len <= 54) {
8669 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
8672 wfex = (WAVEFORMATEX *) (owma_data + 36);
8673 buf = gst_buffer_new_and_alloc (owma_len - 54);
8674 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
8675 if (wfex->wFormatTag == 0x0161) {
8676 codec_name = "Windows Media Audio";
8678 } else if (wfex->wFormatTag == 0x0162) {
8679 codec_name = "Windows Media Audio 9 Pro";
8681 } else if (wfex->wFormatTag == 0x0163) {
8682 codec_name = "Windows Media Audio 9 Lossless";
8683 /* is that correct? gstffmpegcodecmap.c is missing it, but
8684 * fluendo codec seems to support it */
8688 gst_caps_set_simple (stream->caps,
8689 "codec_data", GST_TYPE_BUFFER, buf,
8690 "wmaversion", G_TYPE_INT, version,
8691 "block_align", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->nBlockAlign),
8692 "bitrate", G_TYPE_INT, GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec),
8693 "width", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
8694 "depth", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
8696 gst_buffer_unref (buf);
8700 codec = g_strdup (codec_name);
8704 case GST_MAKE_FOURCC ('w', 'm', 'a', ' '):
8706 gint len = QT_UINT32 (stsd_data) - offset;
8707 const guint8 *wfex_data = stsd_data + offset;
8708 const gchar *codec_name = NULL;
8710 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
8711 /* FIXME this should also be gst_riff_strf_auds,
8712 * but the latter one is actually missing bits-per-sample :( */
8717 gint32 nSamplesPerSec;
8718 gint32 nAvgBytesPerSec;
8720 gint16 wBitsPerSample;
8725 /* FIXME: unify with similar wavformatex parsing code above */
8726 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
8732 if (QT_UINT32 (wfex_data) <= len)
8733 size = QT_UINT32 (wfex_data) - 8;
8738 /* No real data, so break out */
8741 switch (QT_FOURCC (wfex_data + 4)) {
8742 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
8744 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
8749 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
8750 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
8751 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
8752 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
8753 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
8754 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
8755 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
8757 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
8758 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
8759 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
8760 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
8761 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
8762 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
8764 if (wfex.wFormatTag == 0x0161) {
8765 codec_name = "Windows Media Audio";
8767 } else if (wfex.wFormatTag == 0x0162) {
8768 codec_name = "Windows Media Audio 9 Pro";
8770 } else if (wfex.wFormatTag == 0x0163) {
8771 codec_name = "Windows Media Audio 9 Lossless";
8772 /* is that correct? gstffmpegcodecmap.c is missing it, but
8773 * fluendo codec seems to support it */
8777 gst_caps_set_simple (stream->caps,
8778 "wmaversion", G_TYPE_INT, version,
8779 "block_align", G_TYPE_INT, wfex.nBlockAlign,
8780 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
8781 "width", G_TYPE_INT, wfex.wBitsPerSample,
8782 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
8784 if (size > wfex.cbSize) {
8787 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
8788 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
8789 size - wfex.cbSize);
8790 gst_caps_set_simple (stream->caps,
8791 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8792 gst_buffer_unref (buf);
8794 GST_WARNING_OBJECT (qtdemux, "no codec data");
8799 codec = g_strdup (codec_name);
8807 wfex_data += size + 8;
8820 list = gst_tag_list_new_empty ();
8821 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
8822 GST_TAG_AUDIO_CODEC, codec, NULL);
8826 /* some bitrate info may have ended up in caps */
8827 s = gst_caps_get_structure (stream->caps, 0);
8828 gst_structure_get_int (s, "bitrate", &bitrate);
8830 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
8834 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
8838 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
8840 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
8842 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
8846 /* If the fourcc's bottom 16 bits gives 'sm', then the top
8847 16 bits is a byte-swapped wave-style codec identifier,
8848 and we can find a WAVE header internally to a 'wave' atom here.
8849 This can more clearly be thought of as 'ms' as the top 16 bits, and a
8850 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
8853 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
8854 if (len < offset + 20) {
8855 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
8857 guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
8858 const guint8 *data = stsd_data + offset + 16;
8860 GNode *waveheadernode;
8862 wavenode = g_node_new ((guint8 *) data);
8863 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
8864 const guint8 *waveheader;
8867 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
8868 if (waveheadernode) {
8869 waveheader = (const guint8 *) waveheadernode->data;
8870 headerlen = QT_UINT32 (waveheader);
8872 if (headerlen > 8) {
8873 gst_riff_strf_auds *header = NULL;
8874 GstBuffer *headerbuf;
8880 headerbuf = gst_buffer_new_and_alloc (headerlen);
8881 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
8883 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
8884 headerbuf, &header, &extra)) {
8885 gst_caps_unref (stream->caps);
8886 /* FIXME: Need to do something with the channel reorder map */
8887 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
8888 header, extra, NULL, NULL, NULL);
8891 gst_buffer_unref (extra);
8896 GST_DEBUG ("Didn't find waveheadernode for this codec");
8898 g_node_destroy (wavenode);
8901 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
8905 /* FIXME: what is in the chunk? */
8908 gint len = QT_UINT32 (stsd_data);
8910 /* seems to be always = 116 = 0x74 */
8916 gint len = QT_UINT32 (stsd_data);
8919 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
8921 gst_buffer_fill (buf, 0, stsd_data + 0x4C, len - 0x4C);
8922 gst_caps_set_simple (stream->caps,
8923 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8924 gst_buffer_unref (buf);
8926 gst_caps_set_simple (stream->caps,
8927 "samplesize", G_TYPE_INT, samplesize, NULL);
8932 GNode *alac, *wave = NULL;
8934 /* apparently, m4a has this atom appended directly in the stsd entry,
8935 * while mov has it in a wave atom */
8936 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
8938 /* alac now refers to stsd entry atom */
8939 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
8941 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
8943 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
8946 const guint8 *alac_data = alac->data;
8947 gint len = QT_UINT32 (alac->data);
8951 GST_DEBUG_OBJECT (qtdemux,
8952 "discarding alac atom with unexpected len %d", len);
8954 /* codec-data contains alac atom size and prefix,
8955 * ffmpeg likes it that way, not quite gst-ish though ...*/
8956 buf = gst_buffer_new_and_alloc (len);
8957 gst_buffer_fill (buf, 0, alac->data, len);
8958 gst_caps_set_simple (stream->caps,
8959 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8960 gst_buffer_unref (buf);
8962 stream->bytes_per_frame = QT_UINT32 (alac_data + 12);
8963 stream->n_channels = QT_UINT8 (alac_data + 21);
8964 stream->rate = QT_UINT32 (alac_data + 32);
8967 gst_caps_set_simple (stream->caps,
8968 "samplesize", G_TYPE_INT, samplesize, NULL);
8976 gint len = QT_UINT32 (stsd_data);
8979 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
8982 gst_buffer_fill (buf, 0, stsd_data + 0x34, len - 0x34);
8984 /* If we have enough data, let's try to get the 'damr' atom. See
8985 * the 3GPP container spec (26.244) for more details. */
8986 if ((len - 0x34) > 8 &&
8987 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
8989 list = gst_tag_list_new_empty ();
8990 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
8991 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
8994 gst_caps_set_simple (stream->caps,
8995 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8996 gst_buffer_unref (buf);
9002 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
9003 gint len = QT_UINT32 (stsd_data);
9006 guint16 sound_version = QT_UINT16 (stsd_data + 32);
9008 if (sound_version == 1) {
9009 guint16 channels = QT_UINT16 (stsd_data + 40);
9010 guint32 time_scale = QT_UINT32 (stsd_data + 46);
9011 guint8 codec_data[2];
9013 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
9015 gint sample_rate_index =
9016 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
9018 /* build AAC codec data */
9019 codec_data[0] = profile << 3;
9020 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
9021 codec_data[1] = (sample_rate_index & 0x01) << 7;
9022 codec_data[1] |= (channels & 0xF) << 3;
9024 buf = gst_buffer_new_and_alloc (2);
9025 gst_buffer_fill (buf, 0, codec_data, 2);
9026 gst_caps_set_simple (stream->caps,
9027 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9028 gst_buffer_unref (buf);
9034 GST_INFO_OBJECT (qtdemux,
9035 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
9039 GST_INFO_OBJECT (qtdemux,
9040 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
9041 GST_FOURCC_ARGS (fourcc), stream->caps);
9043 } else if (stream->subtype == FOURCC_strm) {
9044 if (fourcc == FOURCC_rtsp) {
9045 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
9047 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
9048 GST_FOURCC_ARGS (fourcc));
9049 goto unknown_stream;
9051 stream->sampled = TRUE;
9052 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
9053 || stream->subtype == FOURCC_sbtl) {
9055 stream->sampled = TRUE;
9056 stream->sparse = TRUE;
9059 qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
9061 list = gst_tag_list_new_empty ();
9062 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
9063 GST_TAG_SUBTITLE_CODEC, codec, NULL);
9068 /* hunt for sort-of codec data */
9075 /* look for palette in a stsd->mp4s->esds sub-atom */
9076 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
9078 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
9081 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
9085 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
9089 GST_INFO_OBJECT (qtdemux,
9090 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
9093 GST_INFO_OBJECT (qtdemux,
9094 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
9095 GST_FOURCC_ARGS (fourcc), stream->caps);
9097 /* everything in 1 sample */
9098 stream->sampled = TRUE;
9101 qtdemux_generic_caps (qtdemux, stream, fourcc, stsd_data, &codec);
9103 if (stream->caps == NULL)
9104 goto unknown_stream;
9107 list = gst_tag_list_new_empty ();
9108 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
9109 GST_TAG_SUBTITLE_CODEC, codec, NULL);
9115 /* promote to sampled format */
9116 if (stream->fourcc == FOURCC_samr) {
9117 /* force mono 8000 Hz for AMR */
9118 stream->sampled = TRUE;
9119 stream->n_channels = 1;
9120 stream->rate = 8000;
9121 } else if (stream->fourcc == FOURCC_sawb) {
9122 /* force mono 16000 Hz for AMR-WB */
9123 stream->sampled = TRUE;
9124 stream->n_channels = 1;
9125 stream->rate = 16000;
9126 } else if (stream->fourcc == FOURCC_mp4a) {
9127 stream->sampled = TRUE;
9130 /* collect sample information */
9131 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
9132 goto samples_failed;
9134 if (qtdemux->fragmented) {
9138 /* need all moov samples as basis; probably not many if any at all */
9139 /* prevent moof parsing taking of at this time */
9140 offset = qtdemux->moof_offset;
9141 qtdemux->moof_offset = 0;
9142 if (stream->n_samples &&
9143 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
9144 qtdemux->moof_offset = offset;
9145 goto samples_failed;
9147 qtdemux->moof_offset = 0;
9148 /* movie duration more reliable in this case (e.g. mehd) */
9149 if (qtdemux->segment.duration &&
9150 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
9152 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
9153 /* need defaults for fragments */
9154 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
9157 /* configure segments */
9158 if (!qtdemux_parse_segments (qtdemux, stream, trak))
9159 goto segments_failed;
9161 /* add some language tag, if useful */
9162 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
9163 strcmp (stream->lang_id, "und")) {
9164 const gchar *lang_code;
9167 list = gst_tag_list_new_empty ();
9169 /* convert ISO 639-2 code to ISO 639-1 */
9170 lang_code = gst_tag_get_language_code (stream->lang_id);
9171 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
9172 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
9175 /* now we are ready to add the stream */
9176 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
9177 goto too_many_streams;
9179 if (!qtdemux->got_moov) {
9180 stream->pending_tags = list;
9181 qtdemux->streams[qtdemux->n_streams] = stream;
9182 qtdemux->n_streams++;
9183 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
9191 GST_INFO_OBJECT (qtdemux, "skip disabled track");
9198 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9199 (_("This file is corrupt and cannot be played.")), (NULL));
9206 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
9214 /* we posted an error already */
9215 /* free stbl sub-atoms */
9216 gst_qtdemux_stbl_free (stream);
9223 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
9231 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
9232 GST_FOURCC_ARGS (stream->subtype));
9239 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
9240 (_("This file contains too many streams. Only playing first %d"),
9241 GST_QTDEMUX_MAX_STREAMS), (NULL));
9246 /* If we can estimate the overall bitrate, and don't have information about the
9247 * stream bitrate for exactly one stream, this guesses the stream bitrate as
9248 * the overall bitrate minus the sum of the bitrates of all other streams. This
9249 * should be useful for the common case where we have one audio and one video
9250 * stream and can estimate the bitrate of one, but not the other. */
9252 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
9254 QtDemuxStream *stream = NULL;
9255 gint64 size, sys_bitrate, sum_bitrate = 0;
9256 GstClockTime duration;
9260 if (qtdemux->fragmented)
9263 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
9265 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
9267 GST_DEBUG_OBJECT (qtdemux,
9268 "Size in bytes of the stream not known - bailing");
9272 /* Subtract the header size */
9273 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
9274 size, qtdemux->header_size);
9276 if (size < qtdemux->header_size)
9279 size = size - qtdemux->header_size;
9281 if (!gst_qtdemux_get_duration (qtdemux, &duration) ||
9282 duration == GST_CLOCK_TIME_NONE) {
9283 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
9287 for (i = 0; i < qtdemux->n_streams; i++) {
9288 switch (qtdemux->streams[i]->subtype) {
9291 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
9292 qtdemux->streams[i]->caps);
9293 /* retrieve bitrate, prefer avg then max */
9295 if (qtdemux->streams[i]->pending_tags) {
9296 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
9297 GST_TAG_MAXIMUM_BITRATE, &bitrate);
9298 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
9299 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
9300 GST_TAG_NOMINAL_BITRATE, &bitrate);
9301 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
9302 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
9303 GST_TAG_BITRATE, &bitrate);
9304 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
9307 sum_bitrate += bitrate;
9310 GST_DEBUG_OBJECT (qtdemux,
9311 ">1 stream with unknown bitrate - bailing");
9314 stream = qtdemux->streams[i];
9318 /* For other subtypes, we assume no significant impact on bitrate */
9324 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
9328 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
9330 if (sys_bitrate < sum_bitrate) {
9331 /* This can happen, since sum_bitrate might be derived from maximum
9332 * bitrates and not average bitrates */
9333 GST_DEBUG_OBJECT (qtdemux,
9334 "System bitrate less than sum bitrate - bailing");
9338 bitrate = sys_bitrate - sum_bitrate;
9339 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
9340 ", Stream bitrate = %u", sys_bitrate, bitrate);
9342 if (!stream->pending_tags)
9343 stream->pending_tags = gst_tag_list_new_empty ();
9345 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9346 GST_TAG_BITRATE, bitrate, NULL);
9349 static GstFlowReturn
9350 qtdemux_prepare_streams (GstQTDemux * qtdemux)
9353 GstFlowReturn ret = GST_FLOW_OK;
9355 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
9357 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
9358 QtDemuxStream *stream = qtdemux->streams[i];
9359 guint32 sample_num = 0;
9361 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
9362 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
9364 if (qtdemux->fragmented) {
9365 /* need all moov samples first */
9366 GST_OBJECT_LOCK (qtdemux);
9367 while (stream->n_samples == 0)
9368 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
9370 GST_OBJECT_UNLOCK (qtdemux);
9372 /* discard any stray moof */
9373 qtdemux->moof_offset = 0;
9376 /* prepare braking */
9377 if (ret != GST_FLOW_ERROR)
9380 /* in pull mode, we should have parsed some sample info by now;
9381 * and quite some code will not handle no samples.
9382 * in push mode, we'll just have to deal with it */
9383 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
9384 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
9385 gst_qtdemux_remove_stream (qtdemux, i);
9390 /* parse the initial sample for use in setting the frame rate cap */
9391 while (sample_num == 0 && sample_num < stream->n_samples) {
9392 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
9396 if (stream->n_samples > 0 && stream->stbl_index > 0) {
9397 stream->first_duration = stream->samples[0].duration;
9398 GST_LOG_OBJECT (qtdemux, "stream %d first duration %u",
9399 stream->track_id, stream->first_duration);
9406 static GstFlowReturn
9407 qtdemux_expose_streams (GstQTDemux * qtdemux)
9410 GstFlowReturn ret = GST_FLOW_OK;
9411 GSList *oldpads = NULL;
9414 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
9416 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
9417 QtDemuxStream *stream = qtdemux->streams[i];
9418 GstPad *oldpad = stream->pad;
9421 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
9422 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
9424 if ((stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl) &&
9425 stream->track_id == qtdemux->chapters_track_id) {
9426 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
9427 so that it doesn't look like a subtitle track */
9428 gst_qtdemux_remove_stream (qtdemux, i);
9433 /* now we have all info and can expose */
9434 list = stream->pending_tags;
9435 stream->pending_tags = NULL;
9437 oldpads = g_slist_prepend (oldpads, oldpad);
9438 gst_qtdemux_add_stream (qtdemux, stream, list);
9441 gst_qtdemux_guess_bitrate (qtdemux);
9443 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
9445 for (iter = oldpads; iter; iter = g_slist_next (iter)) {
9446 GstPad *oldpad = iter->data;
9448 gst_pad_push_event (oldpad, gst_event_new_eos ());
9449 gst_pad_set_active (oldpad, FALSE);
9450 gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
9451 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, oldpad);
9452 gst_object_unref (oldpad);
9455 /* check if we should post a redirect in case there is a single trak
9456 * and it is a redirecting trak */
9457 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
9460 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
9461 "an external content");
9462 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
9463 gst_structure_new ("redirect",
9464 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
9466 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
9467 qtdemux->posted_redirect = TRUE;
9470 for (i = 0; i < qtdemux->n_streams; i++) {
9471 QtDemuxStream *stream = qtdemux->streams[i];
9473 qtdemux_do_allocation (qtdemux, stream);
9476 qtdemux->exposed = TRUE;
9480 /* check if major or compatible brand is 3GP */
9481 static inline gboolean
9482 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
9485 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
9486 GST_MAKE_FOURCC ('3', 'g', 0, 0));
9487 } else if (qtdemux->comp_brands != NULL) {
9491 gboolean res = FALSE;
9493 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
9497 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
9498 GST_MAKE_FOURCC ('3', 'g', 0, 0));
9502 gst_buffer_unmap (qtdemux->comp_brands, &map);
9509 /* check if tag is a spec'ed 3GP tag keyword storing a string */
9510 static inline gboolean
9511 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
9513 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
9514 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
9515 || fourcc == FOURCC_albm;
9519 qtdemux_tag_add_location (GstQTDemux * qtdemux, const char *tag,
9520 const char *dummy, GNode * node)
9522 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
9526 gdouble longitude, latitude, altitude;
9529 len = QT_UINT32 (node->data);
9536 /* TODO: language code skipped */
9538 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
9541 /* do not alarm in trivial case, but bail out otherwise */
9542 if (*(data + offset) != 0) {
9543 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
9547 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9548 GST_TAG_GEO_LOCATION_NAME, name, NULL);
9549 offset += strlen (name);
9553 if (len < offset + 2 + 4 + 4 + 4)
9556 /* +1 +1 = skip null-terminator and location role byte */
9558 /* table in spec says unsigned, semantics say negative has meaning ... */
9559 longitude = QT_SFP32 (data + offset);
9562 latitude = QT_SFP32 (data + offset);
9565 altitude = QT_SFP32 (data + offset);
9567 /* one invalid means all are invalid */
9568 if (longitude >= -180.0 && longitude <= 180.0 &&
9569 latitude >= -90.0 && latitude <= 90.0) {
9570 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9571 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
9572 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
9573 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
9576 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
9583 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
9590 qtdemux_tag_add_year (GstQTDemux * qtdemux, const char *tag, const char *dummy,
9597 len = QT_UINT32 (node->data);
9601 y = QT_UINT16 ((guint8 *) node->data + 12);
9603 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
9606 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
9608 date = g_date_new_dmy (1, 1, y);
9609 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, date, NULL);
9614 qtdemux_tag_add_classification (GstQTDemux * qtdemux, const char *tag,
9615 const char *dummy, GNode * node)
9618 char *tag_str = NULL;
9623 len = QT_UINT32 (node->data);
9628 entity = (guint8 *) node->data + offset;
9629 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
9630 GST_DEBUG_OBJECT (qtdemux,
9631 "classification info: %c%c%c%c invalid classification entity",
9632 entity[0], entity[1], entity[2], entity[3]);
9637 table = QT_UINT16 ((guint8 *) node->data + offset);
9639 /* Language code skipped */
9643 /* Tag format: "XXXX://Y[YYYY]/classification info string"
9644 * XXXX: classification entity, fixed length 4 chars.
9645 * Y[YYYY]: classification table, max 5 chars.
9647 tag_str = g_strdup_printf ("----://%u/%s",
9648 table, (char *) node->data + offset);
9650 /* memcpy To be sure we're preserving byte order */
9651 memcpy (tag_str, entity, 4);
9652 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
9654 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_APPEND, tag,
9664 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
9670 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, const char *tag,
9671 const char *dummy, GNode * node)
9673 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
9679 gboolean ret = TRUE;
9680 const gchar *charset = NULL;
9682 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9684 len = QT_UINT32 (data->data);
9685 type = QT_UINT32 ((guint8 *) data->data + 8);
9686 if (type == 0x00000001 && len > 16) {
9687 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
9690 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
9691 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s,
9695 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
9699 len = QT_UINT32 (node->data);
9700 type = QT_UINT32 ((guint8 *) node->data + 4);
9701 if ((type >> 24) == 0xa9) {
9705 /* Type starts with the (C) symbol, so the next data is a list
9706 * of (string size(16), language code(16), string) */
9708 str_len = QT_UINT16 ((guint8 *) node->data + 8);
9709 lang_code = QT_UINT16 ((guint8 *) node->data + 10);
9711 /* the string + fourcc + size + 2 16bit fields,
9712 * means that there are more tags in this atom */
9713 if (len > str_len + 8 + 4) {
9714 /* TODO how to represent the same tag in different languages? */
9715 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
9716 "text alternatives, reading only first one");
9720 len = str_len + 8 + 4; /* remove trailing strings that we don't use */
9721 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
9723 if (lang_code < 0x800) { /* MAC encoded string */
9726 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
9727 QT_FOURCC ((guint8 *) node->data + 4))) {
9728 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
9730 /* we go for 3GP style encoding if major brands claims so,
9731 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
9732 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
9733 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
9734 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
9736 /* 16-bit Language code is ignored here as well */
9737 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
9744 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
9745 ret = FALSE; /* may have to fallback */
9750 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
9751 charset, NULL, NULL, &err);
9753 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
9754 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
9759 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
9760 len - offset, env_vars);
9763 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
9764 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s, NULL);
9768 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
9775 qtdemux_tag_add_str (GstQTDemux * qtdemux, const char *tag,
9776 const char *dummy, GNode * node)
9778 qtdemux_tag_add_str_full (qtdemux, tag, dummy, node);
9782 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, const char *tag,
9783 const char *dummy, GNode * node)
9785 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
9787 char *s, *t, *k = NULL;
9792 /* first try normal string tag if major brand not 3GP */
9793 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
9794 if (!qtdemux_tag_add_str_full (qtdemux, tag, dummy, node)) {
9795 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
9796 * let's try it 3gpp way after minor safety check */
9798 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
9804 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
9808 len = QT_UINT32 (data);
9812 count = QT_UINT8 (data + 14);
9814 for (; count; count--) {
9817 if (offset + 1 > len)
9819 slen = QT_UINT8 (data + offset);
9821 if (offset + slen > len)
9823 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
9826 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
9828 t = g_strjoin (",", k, s, NULL);
9836 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
9843 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
9844 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, k, NULL);
9853 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
9859 qtdemux_tag_add_num (GstQTDemux * qtdemux, const char *tag1,
9860 const char *tag2, GNode * node)
9867 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9869 len = QT_UINT32 (data->data);
9870 type = QT_UINT32 ((guint8 *) data->data + 8);
9871 if (type == 0x00000000 && len >= 22) {
9872 n1 = QT_UINT16 ((guint8 *) data->data + 18);
9873 n2 = QT_UINT16 ((guint8 *) data->data + 20);
9875 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
9876 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9880 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
9881 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9889 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
9897 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9899 len = QT_UINT32 (data->data);
9900 type = QT_UINT32 ((guint8 *) data->data + 8);
9901 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
9902 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
9903 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
9904 n1 = QT_UINT16 ((guint8 *) data->data + 16);
9906 /* do not add bpm=0 */
9907 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
9908 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9909 tag1, (gdouble) n1, NULL);
9916 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, const char *tag1,
9917 const char *dummy, GNode * node)
9924 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9926 len = QT_UINT32 (data->data);
9927 type = QT_UINT32 ((guint8 *) data->data + 8);
9928 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
9929 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
9930 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
9931 num = QT_UINT32 ((guint8 *) data->data + 16);
9933 /* do not add num=0 */
9934 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
9935 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9943 qtdemux_tag_add_covr (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
9951 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9953 len = QT_UINT32 (data->data);
9954 type = QT_UINT32 ((guint8 *) data->data + 8);
9955 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
9956 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
9958 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
9959 len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
9960 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
9961 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9962 tag1, sample, NULL);
9963 gst_sample_unref (sample);
9970 qtdemux_tag_add_date (GstQTDemux * qtdemux, const char *tag, const char *dummy,
9978 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9980 len = QT_UINT32 (data->data);
9981 type = QT_UINT32 ((guint8 *) data->data + 8);
9982 if (type == 0x00000001 && len > 16) {
9983 guint y, m = 1, d = 1;
9986 s = g_strndup ((char *) data->data + 16, len - 16);
9987 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
9988 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
9989 if (ret >= 1 && y > 1500 && y < 3000) {
9992 date = g_date_new_dmy (d, m, y);
9993 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag,
9997 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
10005 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, const char *tag, const char *dummy,
10010 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
10012 /* re-route to normal string tag if major brand says so
10013 * or no data atom and compatible brand suggests so */
10014 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
10015 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
10016 qtdemux_tag_add_str (qtdemux, tag, dummy, node);
10021 guint len, type, n;
10023 len = QT_UINT32 (data->data);
10024 type = QT_UINT32 ((guint8 *) data->data + 8);
10025 if (type == 0x00000000 && len >= 18) {
10026 n = QT_UINT16 ((guint8 *) data->data + 16);
10028 const gchar *genre;
10030 genre = gst_tag_id3_genre_get (n - 1);
10031 if (genre != NULL) {
10032 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
10033 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
10042 qtdemux_add_double_tag_from_str (GstQTDemux * demux, const gchar * tag,
10043 guint8 * data, guint32 datasize)
10048 /* make a copy to have \0 at the end */
10049 datacopy = g_strndup ((gchar *) data, datasize);
10051 /* convert the str to double */
10052 if (sscanf (datacopy, "%lf", &value) == 1) {
10053 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
10054 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_REPLACE, tag, value, NULL);
10056 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
10064 qtdemux_tag_add_revdns (GstQTDemux * demux, const char *tag,
10065 const char *tag_bis, GNode * node)
10074 const gchar *meanstr;
10075 const gchar *namestr;
10077 /* checking the whole ---- atom size for consistency */
10078 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
10079 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
10083 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
10085 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
10089 meansize = QT_UINT32 (mean->data);
10090 if (meansize <= 12) {
10091 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
10094 meanstr = ((gchar *) mean->data) + 12;
10097 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
10099 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
10103 namesize = QT_UINT32 (name->data);
10104 if (namesize <= 12) {
10105 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
10108 namestr = ((gchar *) name->data) + 12;
10116 * uint24 - data type
10120 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
10122 GST_WARNING_OBJECT (demux, "No data atom in this tag");
10125 datasize = QT_UINT32 (data->data);
10126 if (datasize <= 16) {
10127 GST_WARNING_OBJECT (demux, "Data atom too small");
10130 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
10132 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
10133 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
10134 static const struct
10136 const gchar name[28];
10137 const gchar tag[28];
10140 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
10141 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
10142 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
10143 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
10144 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
10145 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
10146 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
10147 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
10151 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
10152 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
10153 switch (gst_tag_get_type (tags[i].tag)) {
10154 case G_TYPE_DOUBLE:
10155 qtdemux_add_double_tag_from_str (demux, tags[i].tag,
10156 ((guint8 *) data->data) + 16, datasize - 16);
10158 case G_TYPE_STRING:
10159 qtdemux_tag_add_str (demux, tags[i].tag, NULL, node);
10168 if (i == G_N_ELEMENTS (tags))
10178 #ifndef GST_DISABLE_GST_DEBUG
10180 gchar *namestr_dbg;
10181 gchar *meanstr_dbg;
10183 meanstr_dbg = g_strndup (meanstr, meansize);
10184 namestr_dbg = g_strndup (namestr, namesize);
10186 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
10187 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
10189 g_free (namestr_dbg);
10190 g_free (meanstr_dbg);
10197 qtdemux_tag_add_id32 (GstQTDemux * demux, const char *tag,
10198 const char *tag_bis, GNode * node)
10203 GstTagList *taglist = NULL;
10205 GST_LOG_OBJECT (demux, "parsing ID32");
10208 len = GST_READ_UINT32_BE (data);
10210 /* need at least full box and language tag */
10214 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
10215 gst_buffer_fill (buf, 0, data + 14, len - 14);
10217 taglist = gst_tag_list_from_id3v2_tag (buf);
10219 GST_LOG_OBJECT (demux, "parsing ok");
10220 gst_tag_list_insert (demux->tag_list, taglist, GST_TAG_MERGE_KEEP);
10222 GST_LOG_OBJECT (demux, "parsing failed");
10226 gst_tag_list_unref (taglist);
10228 gst_buffer_unref (buf);
10231 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux,
10232 const char *tag, const char *tag_bis, GNode * node);
10235 FOURCC_pcst -> if media is a podcast -> bool
10236 FOURCC_cpil -> if media is part of a compilation -> bool
10237 FOURCC_pgap -> if media is part of a gapless context -> bool
10238 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
10241 static const struct
10244 const gchar *gst_tag;
10245 const gchar *gst_tag_bis;
10246 const GstQTDemuxAddTagFunc func;
10249 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
10250 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
10251 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
10252 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
10253 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
10254 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
10255 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
10256 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
10257 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
10258 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
10259 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
10260 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
10261 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
10262 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
10263 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
10264 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
10265 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
10266 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
10267 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
10268 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
10269 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
10270 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
10271 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
10272 qtdemux_tag_add_num}, {
10273 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
10274 qtdemux_tag_add_num}, {
10275 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
10276 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
10277 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
10278 FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
10279 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
10280 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
10281 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
10282 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
10283 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
10284 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
10285 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
10286 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
10287 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
10288 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
10289 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
10290 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
10291 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
10292 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
10293 qtdemux_tag_add_classification}, {
10294 FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
10295 FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
10296 FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
10298 /* This is a special case, some tags are stored in this
10299 * 'reverse dns naming', according to:
10300 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
10303 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
10304 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
10305 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
10309 qtdemux_tag_add_blob (GNode * node, GstQTDemux * demux)
10315 const gchar *style;
10322 len = QT_UINT32 (data);
10323 buf = gst_buffer_new_and_alloc (len);
10324 gst_buffer_fill (buf, 0, data, len);
10326 /* heuristic to determine style of tag */
10327 if (QT_FOURCC (data + 4) == FOURCC_____ ||
10328 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
10330 else if (demux->major_brand == FOURCC_qt__)
10331 style = "quicktime";
10332 /* fall back to assuming iso/3gp tag style */
10336 /* santize the name for the caps. */
10337 for (i = 0; i < 4; i++) {
10338 guint8 d = data[4 + i];
10339 if (g_ascii_isalnum (d))
10340 ndata[i] = g_ascii_tolower (d);
10345 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
10346 ndata[0], ndata[1], ndata[2], ndata[3]);
10347 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
10349 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
10350 sample = gst_sample_new (buf, NULL, NULL, s);
10351 gst_buffer_unref (buf);
10352 g_free (media_type);
10354 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
10357 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_APPEND,
10358 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
10360 gst_sample_unref (sample);
10364 qtdemux_parse_udta (GstQTDemux * qtdemux, GNode * udta)
10372 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
10373 if (meta != NULL) {
10374 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
10375 if (ilst == NULL) {
10376 GST_LOG_OBJECT (qtdemux, "no ilst");
10381 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
10384 GST_DEBUG_OBJECT (qtdemux, "new tag list");
10385 if (!qtdemux->tag_list) {
10386 qtdemux->tag_list = gst_tag_list_new_empty ();
10387 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
10389 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
10393 while (i < G_N_ELEMENTS (add_funcs)) {
10394 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
10398 len = QT_UINT32 (node->data);
10400 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
10401 GST_FOURCC_ARGS (add_funcs[i].fourcc));
10403 add_funcs[i].func (qtdemux, add_funcs[i].gst_tag,
10404 add_funcs[i].gst_tag_bis, node);
10406 g_node_destroy (node);
10412 /* parsed nodes have been removed, pass along remainder as blob */
10413 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
10414 (GNodeForeachFunc) qtdemux_tag_add_blob, qtdemux);
10416 /* parse up XMP_ node if existing */
10417 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
10418 if (xmp_ != NULL) {
10420 GstTagList *taglist;
10422 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
10423 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
10424 taglist = gst_tag_list_from_xmp_buffer (buf);
10425 gst_buffer_unref (buf);
10427 qtdemux_handle_xmp_taglist (qtdemux, taglist);
10429 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
10436 GstStructure *structure; /* helper for sort function */
10438 guint min_req_bitrate;
10439 guint min_req_qt_version;
10443 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
10445 GstQtReference *ref_a = (GstQtReference *) a;
10446 GstQtReference *ref_b = (GstQtReference *) b;
10448 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
10449 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
10451 /* known bitrates go before unknown; higher bitrates go first */
10452 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
10455 /* sort the redirects and post a message for the application.
10458 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
10460 GstQtReference *best;
10463 GValue list_val = { 0, };
10466 g_assert (references != NULL);
10468 references = g_list_sort (references, qtdemux_redirects_sort_func);
10470 best = (GstQtReference *) references->data;
10472 g_value_init (&list_val, GST_TYPE_LIST);
10474 for (l = references; l != NULL; l = l->next) {
10475 GstQtReference *ref = (GstQtReference *) l->data;
10476 GValue struct_val = { 0, };
10478 ref->structure = gst_structure_new ("redirect",
10479 "new-location", G_TYPE_STRING, ref->location, NULL);
10481 if (ref->min_req_bitrate > 0) {
10482 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
10483 ref->min_req_bitrate, NULL);
10486 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
10487 g_value_set_boxed (&struct_val, ref->structure);
10488 gst_value_list_append_value (&list_val, &struct_val);
10489 g_value_unset (&struct_val);
10490 /* don't free anything here yet, since we need best->structure below */
10493 g_assert (best != NULL);
10494 s = gst_structure_copy (best->structure);
10496 if (g_list_length (references) > 1) {
10497 gst_structure_set_value (s, "locations", &list_val);
10500 g_value_unset (&list_val);
10502 for (l = references; l != NULL; l = l->next) {
10503 GstQtReference *ref = (GstQtReference *) l->data;
10505 gst_structure_free (ref->structure);
10506 g_free (ref->location);
10509 g_list_free (references);
10511 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
10512 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
10513 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
10514 qtdemux->posted_redirect = TRUE;
10517 /* look for redirect nodes, collect all redirect information and
10521 qtdemux_parse_redirects (GstQTDemux * qtdemux)
10523 GNode *rmra, *rmda, *rdrf;
10525 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
10527 GList *redirects = NULL;
10529 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
10531 GstQtReference ref = { NULL, NULL, 0, 0 };
10532 GNode *rmdr, *rmvc;
10534 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
10535 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
10536 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
10537 ref.min_req_bitrate);
10540 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
10541 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
10542 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
10544 #ifndef GST_DISABLE_GST_DEBUG
10545 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
10547 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
10549 GST_LOG_OBJECT (qtdemux,
10550 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
10551 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
10552 bitmask, check_type);
10553 if (package == FOURCC_qtim && check_type == 0) {
10554 ref.min_req_qt_version = version;
10558 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
10563 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
10564 ref_data = (guint8 *) rdrf->data + 20;
10565 if (ref_type == FOURCC_alis) {
10566 guint record_len, record_version, fn_len;
10568 /* MacOSX alias record, google for alias-layout.txt */
10569 record_len = QT_UINT16 (ref_data + 4);
10570 record_version = QT_UINT16 (ref_data + 4 + 2);
10571 fn_len = QT_UINT8 (ref_data + 50);
10572 if (record_len > 50 && record_version == 2 && fn_len > 0) {
10573 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
10575 } else if (ref_type == FOURCC_url_) {
10576 ref.location = g_strdup ((gchar *) ref_data);
10578 GST_DEBUG_OBJECT (qtdemux,
10579 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
10580 GST_FOURCC_ARGS (ref_type));
10582 if (ref.location != NULL) {
10583 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
10584 redirects = g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
10586 GST_WARNING_OBJECT (qtdemux,
10587 "Failed to extract redirect location from rdrf atom");
10591 /* look for others */
10592 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
10595 if (redirects != NULL) {
10596 qtdemux_process_redirects (qtdemux, redirects);
10602 static GstTagList *
10603 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
10607 if (tags == NULL) {
10608 tags = gst_tag_list_new_empty ();
10609 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
10612 if (qtdemux->major_brand == FOURCC_mjp2)
10613 fmt = "Motion JPEG 2000";
10614 else if ((qtdemux->major_brand & 0xffff) == GST_MAKE_FOURCC ('3', 'g', 0, 0))
10616 else if (qtdemux->major_brand == FOURCC_qt__)
10618 else if (qtdemux->fragmented)
10621 fmt = "ISO MP4/M4A";
10623 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
10624 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
10626 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
10632 /* we have read th complete moov node now.
10633 * This function parses all of the relevant info, creates the traks and
10634 * prepares all data structures for playback
10637 qtdemux_parse_tree (GstQTDemux * qtdemux)
10643 GstClockTime duration;
10644 guint64 creation_time;
10645 GstDateTime *datetime = NULL;
10648 /* make sure we have a usable taglist */
10649 if (!qtdemux->tag_list) {
10650 qtdemux->tag_list = gst_tag_list_new_empty ();
10651 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
10653 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
10656 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
10657 if (mvhd == NULL) {
10658 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
10659 return qtdemux_parse_redirects (qtdemux);
10662 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
10663 if (version == 1) {
10664 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
10665 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
10666 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
10667 } else if (version == 0) {
10668 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
10669 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
10670 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
10672 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
10676 /* Moving qt creation time (secs since 1904) to unix time */
10677 if (creation_time != 0) {
10678 /* Try to use epoch first as it should be faster and more commonly found */
10679 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
10682 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
10683 /* some data cleansing sanity */
10684 g_get_current_time (&now);
10685 if (now.tv_sec + 24 * 3600 < creation_time) {
10686 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
10688 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
10691 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
10692 GDateTime *dt, *dt_local;
10694 dt = g_date_time_add_seconds (base_dt, creation_time);
10695 dt_local = g_date_time_to_local (dt);
10696 datetime = gst_date_time_new_from_g_date_time (dt_local);
10698 g_date_time_unref (base_dt);
10699 g_date_time_unref (dt);
10703 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
10704 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
10706 gst_date_time_unref (datetime);
10709 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
10710 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
10712 /* check for fragmented file and get some (default) data */
10713 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
10716 GstByteReader mehd_data;
10718 /* let track parsing or anyone know weird stuff might happen ... */
10719 qtdemux->fragmented = TRUE;
10721 /* compensate for total duration */
10722 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
10724 qtdemux_parse_mehd (qtdemux, &mehd_data);
10727 /* set duration in the segment info */
10728 gst_qtdemux_get_duration (qtdemux, &duration);
10730 qtdemux->segment.duration = duration;
10731 /* also do not exceed duration; stop is set that way post seek anyway,
10732 * and segment activation falls back to duration,
10733 * whereas loop only checks stop, so let's align this here as well */
10734 qtdemux->segment.stop = duration;
10737 /* parse all traks */
10738 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
10740 qtdemux_parse_trak (qtdemux, trak);
10741 /* iterate all siblings */
10742 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
10746 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
10748 qtdemux_parse_udta (qtdemux, udta);
10750 GST_LOG_OBJECT (qtdemux, "No udta node found.");
10753 /* maybe also some tags in meta box */
10754 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
10756 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
10757 qtdemux_parse_udta (qtdemux, udta);
10759 GST_LOG_OBJECT (qtdemux, "No meta node found.");
10762 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
10767 /* taken from ffmpeg */
10769 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
10781 len = (len << 7) | (c & 0x7f);
10789 /* this can change the codec originally present in @list */
10791 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
10792 GNode * esds, GstTagList * list)
10794 int len = QT_UINT32 (esds->data);
10795 guint8 *ptr = esds->data;
10796 guint8 *end = ptr + len;
10798 guint8 *data_ptr = NULL;
10800 guint8 object_type_id = 0;
10801 const char *codec_name = NULL;
10802 GstCaps *caps = NULL;
10804 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
10806 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
10808 while (ptr + 1 < end) {
10809 tag = QT_UINT8 (ptr);
10810 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
10812 len = read_descr_size (ptr, end, &ptr);
10813 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
10815 /* Check the stated amount of data is available for reading */
10816 if (len < 0 || ptr + len > end)
10820 case ES_DESCRIPTOR_TAG:
10821 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
10822 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
10825 case DECODER_CONFIG_DESC_TAG:{
10826 guint max_bitrate, avg_bitrate;
10828 object_type_id = QT_UINT8 (ptr);
10829 max_bitrate = QT_UINT32 (ptr + 5);
10830 avg_bitrate = QT_UINT32 (ptr + 9);
10831 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
10832 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
10833 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
10834 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
10835 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
10836 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
10837 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
10838 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
10840 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
10841 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
10842 avg_bitrate, NULL);
10847 case DECODER_SPECIFIC_INFO_TAG:
10848 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
10849 if (object_type_id == 0xe0 && len == 0x40) {
10855 GST_DEBUG_OBJECT (qtdemux,
10856 "Have VOBSUB palette. Creating palette event");
10857 /* move to decConfigDescr data and read palette */
10859 for (i = 0; i < 16; i++) {
10860 clut[i] = QT_UINT32 (data);
10864 s = gst_structure_new ("application/x-gst-dvd", "event",
10865 G_TYPE_STRING, "dvd-spu-clut-change",
10866 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
10867 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
10868 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
10869 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
10870 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
10871 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
10872 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
10873 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
10876 /* store event and trigger custom processing */
10877 stream->pending_event =
10878 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
10880 /* Generic codec_data handler puts it on the caps */
10887 case SL_CONFIG_DESC_TAG:
10888 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
10892 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
10894 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
10900 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
10901 * in use, and should also be used to override some other parameters for some
10903 switch (object_type_id) {
10904 case 0x20: /* MPEG-4 */
10905 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
10906 * profile_and_level_indication */
10907 if (data_ptr != NULL && data_len >= 5 &&
10908 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
10909 gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
10910 data_ptr + 4, data_len - 4);
10912 break; /* Nothing special needed here */
10913 case 0x21: /* H.264 */
10914 codec_name = "H.264 / AVC";
10915 caps = gst_caps_new_simple ("video/x-h264",
10916 "stream-format", G_TYPE_STRING, "avc",
10917 "alignment", G_TYPE_STRING, "au", NULL);
10919 case 0x40: /* AAC (any) */
10920 case 0x66: /* AAC Main */
10921 case 0x67: /* AAC LC */
10922 case 0x68: /* AAC SSR */
10923 /* Override channels and rate based on the codec_data, as it's often
10925 /* Only do so for basic setup without HE-AAC extension */
10926 if (data_ptr && data_len == 2) {
10927 guint channels, rateindex, rate;
10929 /* FIXME: add gst_codec_utils_aac_get_{channels|sample_rate}()? */
10930 channels = (data_ptr[1] & 0x7f) >> 3;
10931 if (channels > 0 && channels < 7) {
10932 stream->n_channels = channels;
10933 } else if (channels == 7) {
10934 stream->n_channels = 8;
10937 rateindex = ((data_ptr[0] & 0x7) << 1) | ((data_ptr[1] & 0x80) >> 7);
10938 rate = gst_codec_utils_aac_get_sample_rate_from_index (rateindex);
10940 stream->rate = rate;
10943 /* Set level and profile if possible */
10944 if (data_ptr != NULL && data_len >= 2) {
10945 gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
10946 data_ptr, data_len);
10949 case 0x60: /* MPEG-2, various profiles */
10955 codec_name = "MPEG-2 video";
10956 caps = gst_caps_new_simple ("video/mpeg",
10957 "mpegversion", G_TYPE_INT, 2,
10958 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
10960 case 0x69: /* MPEG-2 BC audio */
10961 case 0x6B: /* MPEG-1 audio */
10962 caps = gst_caps_new_simple ("audio/mpeg",
10963 "mpegversion", G_TYPE_INT, 1, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
10964 codec_name = "MPEG-1 audio";
10966 case 0x6A: /* MPEG-1 */
10967 codec_name = "MPEG-1 video";
10968 caps = gst_caps_new_simple ("video/mpeg",
10969 "mpegversion", G_TYPE_INT, 1,
10970 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
10972 case 0x6C: /* MJPEG */
10974 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
10976 codec_name = "Motion-JPEG";
10978 case 0x6D: /* PNG */
10980 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
10982 codec_name = "PNG still images";
10984 case 0x6E: /* JPEG2000 */
10985 codec_name = "JPEG-2000";
10986 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
10988 case 0xA4: /* Dirac */
10989 codec_name = "Dirac";
10990 caps = gst_caps_new_empty_simple ("video/x-dirac");
10992 case 0xA5: /* AC3 */
10993 codec_name = "AC-3 audio";
10994 caps = gst_caps_new_simple ("audio/x-ac3",
10995 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
10997 case 0xA9: /* AC3 */
10998 codec_name = "DTS audio";
10999 caps = gst_caps_new_simple ("audio/x-dts",
11000 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
11002 case 0xE1: /* QCELP */
11003 /* QCELP, the codec_data is a riff tag (little endian) with
11004 * 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). */
11005 caps = gst_caps_new_empty_simple ("audio/qcelp");
11006 codec_name = "QCELP";
11012 /* If we have a replacement caps, then change our caps for this stream */
11014 gst_caps_unref (stream->caps);
11015 stream->caps = caps;
11018 if (codec_name && list)
11019 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
11020 GST_TAG_AUDIO_CODEC, codec_name, NULL);
11022 /* Add the codec_data attribute to caps, if we have it */
11026 buffer = gst_buffer_new_and_alloc (data_len);
11027 gst_buffer_fill (buffer, 0, data_ptr, data_len);
11029 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
11030 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
11032 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
11034 gst_buffer_unref (buffer);
11039 #define _codec(name) \
11041 if (codec_name) { \
11042 *codec_name = g_strdup (name); \
11047 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
11048 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
11050 GstCaps *caps = NULL;
11051 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
11054 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
11055 _codec ("PNG still images");
11056 caps = gst_caps_new_empty_simple ("image/png");
11058 case GST_MAKE_FOURCC ('j', 'p', 'e', 'g'):
11059 _codec ("JPEG still images");
11061 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
11064 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
11065 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
11066 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
11067 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
11068 _codec ("Motion-JPEG");
11070 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
11073 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
11074 _codec ("Motion-JPEG format B");
11075 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
11077 case GST_MAKE_FOURCC ('m', 'j', 'p', '2'):
11078 _codec ("JPEG-2000");
11079 /* override to what it should be according to spec, avoid palette_data */
11080 stream->bits_per_sample = 24;
11081 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
11083 case GST_MAKE_FOURCC ('S', 'V', 'Q', '3'):
11084 _codec ("Sorensen video v.3");
11085 caps = gst_caps_new_simple ("video/x-svq",
11086 "svqversion", G_TYPE_INT, 3, NULL);
11088 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
11089 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
11090 _codec ("Sorensen video v.1");
11091 caps = gst_caps_new_simple ("video/x-svq",
11092 "svqversion", G_TYPE_INT, 1, NULL);
11094 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
11095 caps = gst_caps_new_empty_simple ("video/x-raw");
11096 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
11097 _codec ("Windows Raw RGB");
11099 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
11103 bps = QT_UINT16 (stsd_data + 98);
11106 format = GST_VIDEO_FORMAT_RGB15;
11109 format = GST_VIDEO_FORMAT_RGB16;
11112 format = GST_VIDEO_FORMAT_RGB;
11115 format = GST_VIDEO_FORMAT_ARGB;
11123 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
11124 format = GST_VIDEO_FORMAT_I420;
11126 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
11127 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
11128 format = GST_VIDEO_FORMAT_I420;
11130 case GST_MAKE_FOURCC ('2', 'v', 'u', 'y'):
11131 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
11132 format = GST_VIDEO_FORMAT_UYVY;
11134 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
11135 format = GST_VIDEO_FORMAT_v308;
11137 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
11138 format = GST_VIDEO_FORMAT_v216;
11140 case GST_MAKE_FOURCC ('v', '2', '1', '0'):
11141 format = GST_VIDEO_FORMAT_v210;
11143 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
11144 format = GST_VIDEO_FORMAT_r210;
11146 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
11147 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
11148 format = GST_VIDEO_FORMAT_v410;
11151 /* Packed YUV 4:4:4:4 8 bit in 32 bits
11152 * but different order than AYUV
11153 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
11154 format = GST_VIDEO_FORMAT_v408;
11157 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
11158 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
11159 _codec ("MPEG-1 video");
11160 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
11161 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11163 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
11164 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
11165 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
11166 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
11167 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
11168 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
11169 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
11170 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
11171 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
11172 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
11173 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
11174 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
11175 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
11176 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
11177 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
11178 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
11179 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
11180 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
11181 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
11182 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
11183 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
11184 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
11185 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
11186 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
11187 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
11188 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
11189 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
11190 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
11191 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
11192 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
11193 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
11194 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
11195 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
11196 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
11197 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
11198 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
11199 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
11200 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
11201 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
11202 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
11203 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
11204 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
11205 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
11206 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
11207 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
11208 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
11209 _codec ("MPEG-2 video");
11210 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
11211 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11213 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
11214 _codec ("GIF still images");
11215 caps = gst_caps_new_empty_simple ("image/gif");
11217 case GST_MAKE_FOURCC ('h', '2', '6', '3'):
11218 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
11219 case GST_MAKE_FOURCC ('s', '2', '6', '3'):
11220 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
11222 /* ffmpeg uses the height/width props, don't know why */
11223 caps = gst_caps_new_simple ("video/x-h263",
11224 "variant", G_TYPE_STRING, "itu", NULL);
11226 case GST_MAKE_FOURCC ('m', 'p', '4', 'v'):
11227 case GST_MAKE_FOURCC ('M', 'P', '4', 'V'):
11228 _codec ("MPEG-4 video");
11229 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
11230 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11232 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
11233 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
11234 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
11235 caps = gst_caps_new_simple ("video/x-msmpeg",
11236 "msmpegversion", G_TYPE_INT, 43, NULL);
11238 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
11240 caps = gst_caps_new_simple ("video/x-divx",
11241 "divxversion", G_TYPE_INT, 3, NULL);
11243 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
11244 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
11246 caps = gst_caps_new_simple ("video/x-divx",
11247 "divxversion", G_TYPE_INT, 4, NULL);
11249 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
11251 caps = gst_caps_new_simple ("video/x-divx",
11252 "divxversion", G_TYPE_INT, 5, NULL);
11255 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
11256 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
11257 case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
11258 case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
11259 case GST_MAKE_FOURCC ('F', 'M', 'P', '4'):
11260 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
11261 caps = gst_caps_new_simple ("video/mpeg",
11262 "mpegversion", G_TYPE_INT, 4, NULL);
11264 *codec_name = g_strdup ("MPEG-4");
11267 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
11268 _codec ("Cinepak");
11269 caps = gst_caps_new_empty_simple ("video/x-cinepak");
11271 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
11272 _codec ("Apple QuickDraw");
11273 caps = gst_caps_new_empty_simple ("video/x-qdrw");
11275 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
11276 _codec ("Apple video");
11277 caps = gst_caps_new_empty_simple ("video/x-apple-video");
11279 case GST_MAKE_FOURCC ('H', '2', '6', '4'):
11280 case GST_MAKE_FOURCC ('a', 'v', 'c', '1'):
11281 _codec ("H.264 / AVC");
11282 caps = gst_caps_new_simple ("video/x-h264",
11283 "stream-format", G_TYPE_STRING, "avc",
11284 "alignment", G_TYPE_STRING, "au", NULL);
11286 case GST_MAKE_FOURCC ('a', 'v', 'c', '3'):
11287 _codec ("H.264 / AVC");
11288 caps = gst_caps_new_simple ("video/x-h264",
11289 "stream-format", G_TYPE_STRING, "avc3",
11290 "alignment", G_TYPE_STRING, "au", NULL);
11292 case GST_MAKE_FOURCC ('H', '2', '6', '5'):
11293 case GST_MAKE_FOURCC ('h', 'v', 'c', '1'):
11294 _codec ("H.265 / HEVC");
11295 caps = gst_caps_new_simple ("video/x-h265",
11296 "stream-format", G_TYPE_STRING, "hvc1",
11297 "alignment", G_TYPE_STRING, "au", NULL);
11299 case GST_MAKE_FOURCC ('h', 'e', 'v', '1'):
11300 _codec ("H.265 / HEVC");
11301 caps = gst_caps_new_simple ("video/x-h265",
11302 "stream-format", G_TYPE_STRING, "hev1",
11303 "alignment", G_TYPE_STRING, "au", NULL);
11305 case GST_MAKE_FOURCC ('r', 'l', 'e', ' '):
11306 _codec ("Run-length encoding");
11307 caps = gst_caps_new_simple ("video/x-rle",
11308 "layout", G_TYPE_STRING, "quicktime", NULL);
11310 case GST_MAKE_FOURCC ('W', 'R', 'L', 'E'):
11311 _codec ("Run-length encoding");
11312 caps = gst_caps_new_simple ("video/x-rle",
11313 "layout", G_TYPE_STRING, "microsoft", NULL);
11315 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
11316 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
11317 _codec ("Indeo Video 3");
11318 caps = gst_caps_new_simple ("video/x-indeo",
11319 "indeoversion", G_TYPE_INT, 3, NULL);
11321 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
11322 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
11323 _codec ("Intel Video 4");
11324 caps = gst_caps_new_simple ("video/x-indeo",
11325 "indeoversion", G_TYPE_INT, 4, NULL);
11327 case GST_MAKE_FOURCC ('d', 'v', 'c', 'p'):
11328 case GST_MAKE_FOURCC ('d', 'v', 'c', ' '):
11329 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
11330 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
11331 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
11332 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
11333 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
11334 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
11335 _codec ("DV Video");
11336 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
11337 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11339 case GST_MAKE_FOURCC ('d', 'v', '5', 'n'): /* DVCPRO50 NTSC */
11340 case GST_MAKE_FOURCC ('d', 'v', '5', 'p'): /* DVCPRO50 PAL */
11341 _codec ("DVCPro50 Video");
11342 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
11343 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11345 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
11346 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
11347 _codec ("DVCProHD Video");
11348 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
11349 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11351 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
11352 _codec ("Apple Graphics (SMC)");
11353 caps = gst_caps_new_empty_simple ("video/x-smc");
11355 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
11357 caps = gst_caps_new_empty_simple ("video/x-vp3");
11359 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
11360 _codec ("VP6 Flash");
11361 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
11363 case GST_MAKE_FOURCC ('X', 'i', 'T', 'h'):
11365 caps = gst_caps_new_empty_simple ("video/x-theora");
11366 /* theora uses one byte of padding in the data stream because it does not
11367 * allow 0 sized packets while theora does */
11368 stream->padding = 1;
11370 case GST_MAKE_FOURCC ('d', 'r', 'a', 'c'):
11372 caps = gst_caps_new_empty_simple ("video/x-dirac");
11374 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
11375 _codec ("TIFF still images");
11376 caps = gst_caps_new_empty_simple ("image/tiff");
11378 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
11379 _codec ("Apple Intermediate Codec");
11380 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
11382 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
11383 _codec ("AVID DNxHD");
11384 caps = gst_caps_from_string ("video/x-dnxhd");
11386 case GST_MAKE_FOURCC ('V', 'P', '8', '0'):
11387 _codec ("On2 VP8");
11388 caps = gst_caps_from_string ("video/x-vp8");
11390 case GST_MAKE_FOURCC ('a', 'p', 'c', 's'):
11391 _codec ("Apple ProRes LT");
11393 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
11396 case GST_MAKE_FOURCC ('a', 'p', 'c', 'h'):
11397 _codec ("Apple ProRes HQ");
11399 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
11402 case GST_MAKE_FOURCC ('a', 'p', 'c', 'n'):
11403 _codec ("Apple ProRes");
11405 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
11408 case GST_MAKE_FOURCC ('a', 'p', 'c', 'o'):
11409 _codec ("Apple ProRes Proxy");
11411 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
11414 case GST_MAKE_FOURCC ('a', 'p', '4', 'h'):
11415 _codec ("Apple ProRes 4444");
11417 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
11420 case GST_MAKE_FOURCC ('v', 'c', '-', '1'):
11423 caps = gst_caps_new_simple ("video/x-wmv",
11424 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
11426 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
11429 char *s, fourstr[5];
11431 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11432 s = g_strdup_printf ("video/x-gst-fourcc-%s", g_strstrip (fourstr));
11433 caps = gst_caps_new_empty_simple (s);
11438 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
11441 gst_video_info_init (&info);
11442 gst_video_info_set_format (&info, format, stream->width, stream->height);
11443 caps = gst_video_info_to_caps (&info);
11444 *codec_name = gst_pb_utils_get_codec_description (caps);
11446 /* enable clipping for raw video streams */
11447 stream->need_clip = TRUE;
11454 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
11455 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
11458 const GstStructure *s;
11462 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
11465 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
11466 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
11467 _codec ("Raw 8-bit PCM audio");
11468 caps = gst_caps_new_simple ("audio/x-raw",
11469 "format", G_TYPE_STRING, "U8",
11470 "layout", G_TYPE_STRING, "interleaved", NULL);
11472 case GST_MAKE_FOURCC ('t', 'w', 'o', 's'):
11473 endian = G_BIG_ENDIAN;
11475 case GST_MAKE_FOURCC ('s', 'o', 'w', 't'):
11479 GstAudioFormat format;
11482 endian = G_LITTLE_ENDIAN;
11484 depth = stream->bytes_per_packet * 8;
11485 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
11487 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
11491 caps = gst_caps_new_simple ("audio/x-raw",
11492 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
11493 "layout", G_TYPE_STRING, "interleaved", NULL);
11496 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
11497 _codec ("Raw 64-bit floating-point audio");
11498 caps = gst_caps_new_simple ("audio/x-raw",
11499 "format", G_TYPE_STRING, "F64BE",
11500 "layout", G_TYPE_STRING, "interleaved", NULL);
11502 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
11503 _codec ("Raw 32-bit floating-point audio");
11504 caps = gst_caps_new_simple ("audio/x-raw",
11505 "format", G_TYPE_STRING, "F32BE",
11506 "layout", G_TYPE_STRING, "interleaved", NULL);
11509 _codec ("Raw 24-bit PCM audio");
11510 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
11512 caps = gst_caps_new_simple ("audio/x-raw",
11513 "format", G_TYPE_STRING, "S24BE",
11514 "layout", G_TYPE_STRING, "interleaved", NULL);
11516 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
11517 _codec ("Raw 32-bit PCM audio");
11518 caps = gst_caps_new_simple ("audio/x-raw",
11519 "format", G_TYPE_STRING, "S32BE",
11520 "layout", G_TYPE_STRING, "interleaved", NULL);
11522 case GST_MAKE_FOURCC ('u', 'l', 'a', 'w'):
11523 _codec ("Mu-law audio");
11524 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
11526 case GST_MAKE_FOURCC ('a', 'l', 'a', 'w'):
11527 _codec ("A-law audio");
11528 caps = gst_caps_new_empty_simple ("audio/x-alaw");
11532 _codec ("Microsoft ADPCM");
11533 /* Microsoft ADPCM-ACM code 2 */
11534 caps = gst_caps_new_simple ("audio/x-adpcm",
11535 "layout", G_TYPE_STRING, "microsoft", NULL);
11539 _codec ("DVI/IMA ADPCM");
11540 caps = gst_caps_new_simple ("audio/x-adpcm",
11541 "layout", G_TYPE_STRING, "dvi", NULL);
11545 _codec ("DVI/Intel IMA ADPCM");
11546 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
11547 caps = gst_caps_new_simple ("audio/x-adpcm",
11548 "layout", G_TYPE_STRING, "quicktime", NULL);
11552 /* MPEG layer 3, CBR only (pre QT4.1) */
11553 case GST_MAKE_FOURCC ('.', 'm', 'p', '3'):
11554 _codec ("MPEG-1 layer 3");
11555 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
11556 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
11557 "mpegversion", G_TYPE_INT, 1, NULL);
11560 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
11561 _codec ("EAC-3 audio");
11562 caps = gst_caps_new_simple ("audio/x-eac3",
11563 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
11564 stream->sampled = TRUE;
11566 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
11567 case GST_MAKE_FOURCC ('a', 'c', '-', '3'):
11568 _codec ("AC-3 audio");
11569 caps = gst_caps_new_simple ("audio/x-ac3",
11570 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
11571 stream->sampled = TRUE;
11573 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
11574 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
11575 _codec ("DTS audio");
11576 caps = gst_caps_new_simple ("audio/x-dts",
11577 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
11578 stream->sampled = TRUE;
11580 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
11581 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
11582 _codec ("DTS-HD audio");
11583 caps = gst_caps_new_simple ("audio/x-dts",
11584 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
11585 stream->sampled = TRUE;
11587 case GST_MAKE_FOURCC ('M', 'A', 'C', '3'):
11589 caps = gst_caps_new_simple ("audio/x-mace",
11590 "maceversion", G_TYPE_INT, 3, NULL);
11592 case GST_MAKE_FOURCC ('M', 'A', 'C', '6'):
11594 caps = gst_caps_new_simple ("audio/x-mace",
11595 "maceversion", G_TYPE_INT, 6, NULL);
11597 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
11599 caps = gst_caps_new_empty_simple ("application/ogg");
11601 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
11602 _codec ("DV audio");
11603 caps = gst_caps_new_empty_simple ("audio/x-dv");
11605 case GST_MAKE_FOURCC ('m', 'p', '4', 'a'):
11606 _codec ("MPEG-4 AAC audio");
11607 caps = gst_caps_new_simple ("audio/mpeg",
11608 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
11609 "stream-format", G_TYPE_STRING, "raw", NULL);
11611 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
11612 _codec ("QDesign Music");
11613 caps = gst_caps_new_empty_simple ("audio/x-qdm");
11615 case GST_MAKE_FOURCC ('Q', 'D', 'M', '2'):
11616 _codec ("QDesign Music v.2");
11617 /* FIXME: QDesign music version 2 (no constant) */
11618 if (FALSE && data) {
11619 caps = gst_caps_new_simple ("audio/x-qdm2",
11620 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
11621 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
11622 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
11624 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
11627 case GST_MAKE_FOURCC ('a', 'g', 's', 'm'):
11628 _codec ("GSM audio");
11629 caps = gst_caps_new_empty_simple ("audio/x-gsm");
11631 case GST_MAKE_FOURCC ('s', 'a', 'm', 'r'):
11632 _codec ("AMR audio");
11633 caps = gst_caps_new_empty_simple ("audio/AMR");
11635 case GST_MAKE_FOURCC ('s', 'a', 'w', 'b'):
11636 _codec ("AMR-WB audio");
11637 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
11639 case GST_MAKE_FOURCC ('i', 'm', 'a', '4'):
11640 _codec ("Quicktime IMA ADPCM");
11641 caps = gst_caps_new_simple ("audio/x-adpcm",
11642 "layout", G_TYPE_STRING, "quicktime", NULL);
11644 case GST_MAKE_FOURCC ('a', 'l', 'a', 'c'):
11645 _codec ("Apple lossless audio");
11646 caps = gst_caps_new_empty_simple ("audio/x-alac");
11648 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
11649 _codec ("QualComm PureVoice");
11650 caps = gst_caps_from_string ("audio/qcelp");
11652 case GST_MAKE_FOURCC ('w', 'm', 'a', ' '):
11655 caps = gst_caps_new_empty_simple ("audio/x-wma");
11657 case GST_MAKE_FOURCC ('l', 'p', 'c', 'm'):
11662 GstAudioFormat format;
11665 FLAG_IS_FLOAT = 0x1,
11666 FLAG_IS_BIG_ENDIAN = 0x2,
11667 FLAG_IS_SIGNED = 0x4,
11668 FLAG_IS_PACKED = 0x8,
11669 FLAG_IS_ALIGNED_HIGH = 0x10,
11670 FLAG_IS_NON_INTERLEAVED = 0x20
11672 _codec ("Raw LPCM audio");
11674 if (data && len >= 56) {
11675 depth = QT_UINT32 (data + 40);
11676 flags = QT_UINT32 (data + 44);
11677 width = QT_UINT32 (data + 48) * 8 / stream->n_channels;
11679 if ((flags & FLAG_IS_FLOAT) == 0) {
11684 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
11685 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
11686 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
11687 caps = gst_caps_new_simple ("audio/x-raw",
11688 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
11689 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
11690 "non-interleaved" : "interleaved", NULL);
11695 if (flags & FLAG_IS_BIG_ENDIAN)
11696 format = GST_AUDIO_FORMAT_F64BE;
11698 format = GST_AUDIO_FORMAT_F64LE;
11700 if (flags & FLAG_IS_BIG_ENDIAN)
11701 format = GST_AUDIO_FORMAT_F32BE;
11703 format = GST_AUDIO_FORMAT_F32LE;
11705 caps = gst_caps_new_simple ("audio/x-raw",
11706 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
11707 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
11708 "non-interleaved" : "interleaved", NULL);
11712 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
11716 char *s, fourstr[5];
11718 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11719 s = g_strdup_printf ("audio/x-gst-fourcc-%s", g_strstrip (fourstr));
11720 caps = gst_caps_new_empty_simple (s);
11726 GstCaps *templ_caps =
11727 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
11728 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
11729 gst_caps_unref (caps);
11730 gst_caps_unref (templ_caps);
11731 caps = intersection;
11734 /* enable clipping for raw audio streams */
11735 s = gst_caps_get_structure (caps, 0);
11736 name = gst_structure_get_name (s);
11737 if (g_str_has_prefix (name, "audio/x-raw")) {
11738 stream->need_clip = TRUE;
11739 stream->max_buffer_size = 4096 * stream->bytes_per_frame;
11740 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
11746 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
11747 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
11751 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
11754 case GST_MAKE_FOURCC ('m', 'p', '4', 's'):
11755 _codec ("DVD subtitle");
11756 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
11757 stream->need_process = TRUE;
11759 case GST_MAKE_FOURCC ('t', 'e', 'x', 't'):
11760 _codec ("Quicktime timed text");
11762 case GST_MAKE_FOURCC ('t', 'x', '3', 'g'):
11763 _codec ("3GPP timed text");
11765 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
11767 /* actual text piece needs to be extracted */
11768 stream->need_process = TRUE;
11772 char *s, fourstr[5];
11774 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11775 s = g_strdup_printf ("text/x-gst-fourcc-%s", g_strstrip (fourstr));
11776 caps = gst_caps_new_empty_simple (s);
11784 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
11785 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
11790 case GST_MAKE_FOURCC ('m', '1', 'v', ' '):
11791 _codec ("MPEG 1 video");
11792 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
11793 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);