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>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the
21 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
26 * SECTION:element-qtdemux
28 * Demuxes a .mov file into raw or compressed audio and/or video streams.
30 * This element supports both push and pull-based scheduling, depending on the
31 * capabilities of the upstream elements.
34 * <title>Example launch line</title>
36 * 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
37 * ]| Play (parse and decode) a .mov file and try to output it to
38 * an automatically detected soundcard and videosink. If the MOV file contains
39 * compressed audio or video data, this will only work if you have the
40 * right decoder elements/plugins installed.
43 * Last reviewed on 2006-12-29 (0.10.5)
50 #include "gst/gst-i18n-plugin.h"
52 #include <glib/gprintf.h>
53 #include <gst/tag/tag.h>
54 #include <gst/audio/audio.h>
56 #include "qtatomparser.h"
57 #include "qtdemux_types.h"
58 #include "qtdemux_dump.h"
59 #include "qtdemux_fourcc.h"
60 #include "qtdemux_lang.h"
62 #include "qtpalette.h"
64 #include "gst/riff/riff-media.h"
65 #include "gst/riff/riff-read.h"
67 #include <gst/pbutils/pbutils.h>
77 /* max. size considered 'sane' for non-mdat atoms */
78 #define QTDEMUX_MAX_ATOM_SIZE (25*1024*1024)
80 /* if the sample index is larger than this, something is likely wrong */
81 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (50*1024*1024)
83 /* For converting qt creation times to unix epoch times */
84 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
85 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
86 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
87 QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
89 GST_DEBUG_CATEGORY (qtdemux_debug);
91 /*typedef struct _QtNode QtNode; */
92 typedef struct _QtDemuxSegment QtDemuxSegment;
93 typedef struct _QtDemuxSample QtDemuxSample;
102 struct _QtDemuxSample
105 gint32 pts_offset; /* Add this value to timestamp to get the pts */
107 guint64 timestamp; /* DTS In mov time */
108 guint32 duration; /* In mov time */
109 gboolean keyframe; /* TRUE when this packet is a keyframe */
112 /* timestamp is the DTS */
113 #define QTSAMPLE_DTS(stream,sample) gst_util_uint64_scale ((sample)->timestamp,\
114 GST_SECOND, (stream)->timescale)
115 /* timestamp + offset is the PTS */
116 #define QTSAMPLE_PTS(stream,sample) gst_util_uint64_scale ((sample)->timestamp + \
117 (sample)->pts_offset, GST_SECOND, (stream)->timescale)
118 /* timestamp + duration - dts is the duration */
119 #define QTSAMPLE_DUR_DTS(stream,sample,dts) (gst_util_uint64_scale ((sample)->timestamp + \
120 (sample)->duration, GST_SECOND, (stream)->timescale) - (dts));
122 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
125 * Quicktime has tracks and segments. A track is a continuous piece of
126 * multimedia content. The track is not always played from start to finish but
127 * instead, pieces of the track are 'cut out' and played in sequence. This is
128 * what the segments do.
130 * Inside the track we have keyframes (K) and delta frames. The track has its
131 * own timing, which starts from 0 and extends to end. The position in the track
132 * is called the media_time.
134 * The segments now describe the pieces that should be played from this track
135 * and are basically tupples of media_time/duration/rate entries. We can have
136 * multiple segments and they are all played after one another. An example:
138 * segment 1: media_time: 1 second, duration: 1 second, rate 1
139 * segment 2: media_time: 3 second, duration: 2 second, rate 2
141 * To correctly play back this track, one must play: 1 second of media starting
142 * from media_time 1 followed by 2 seconds of media starting from media_time 3
145 * Each of the segments will be played at a specific time, the first segment at
146 * time 0, the second one after the duration of the first one, etc.. Note that
147 * the time in resulting playback is not identical to the media_time of the
150 * Visually, assuming the track has 4 second of media_time:
153 * .-----------------------------------------------------------.
154 * track: | K.....K.........K........K.......K.......K...........K... |
155 * '-----------------------------------------------------------'
157 * .------------^ ^ .----------^ ^
158 * / .-------------' / .------------------'
160 * .--------------. .--------------.
161 * | segment 1 | | segment 2 |
162 * '--------------' '--------------'
164 * The challenge here is to cut out the right pieces of the track for each of
165 * the playback segments. This fortunatly can easily be done with the SEGMENT
166 * events of gstreamer.
168 * For playback of segment 1, we need to provide the decoder with the keyframe
169 * (a), in the above figure, but we must instruct it only to output the decoded
170 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
171 * position set to the time of the segment: 0.
173 * We then proceed to push data from keyframe (a) to frame (b). The decoder
174 * decodes but clips all before media_time 1.
176 * After finishing a segment, we push out a new SEGMENT event with the clipping
177 * boundaries of the new data.
179 * This is a good usecase for the GStreamer accumulated SEGMENT events.
182 struct _QtDemuxSegment
184 /* global time and duration, all gst time */
188 /* media time of trak, all gst time */
194 struct _QtDemuxStream
203 /* if the stream has a redirect URI in its headers, we store it here */
210 guint64 duration; /* in timescale */
214 gchar lang_id[4]; /* ISO 639-2T language code */
218 QtDemuxSample *samples;
219 gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */
220 guint32 min_duration; /* duration in timescale of first sample, used for figuring out
221 the framerate, in timescale units */
222 guint32 offset_in_sample;
223 guint32 max_buffer_size;
225 /* if we use chunks or samples */
237 /* Numerator/denominator framerate */
240 guint16 bits_per_sample;
241 guint16 color_table_id;
246 guint samples_per_packet;
247 guint samples_per_frame;
248 guint bytes_per_packet;
249 guint bytes_per_sample;
250 guint bytes_per_frame;
254 gboolean use_allocator;
255 GstAllocator *allocator;
256 GstAllocationParams params;
258 /* when a discontinuity is pending */
261 /* list of buffers to push first */
264 /* if we need to clip this buffer. This is only needed for uncompressed
268 /* buffer needs some custom processing, e.g. subtitles */
269 gboolean need_process;
271 /* current position */
272 guint32 segment_index;
273 guint32 sample_index;
274 guint64 time_position; /* in gst time */
276 /* the Gst segment we are processing out, used for clipping */
279 /* last GstFlowReturn */
280 GstFlowReturn last_ret;
282 /* quicktime segments */
284 QtDemuxSegment *segments;
289 GstTagList *pending_tags;
290 gboolean send_global_tags;
292 GstEvent *pending_event;
302 gboolean chunks_are_chunks;
306 GstByteReader co_chunk;
308 guint32 current_chunk;
310 guint32 samples_per_chunk;
311 guint32 stco_sample_index;
313 guint32 sample_size; /* 0 means variable sizes are stored in stsz */
316 guint32 n_samples_per_chunk;
317 guint32 stsc_chunk_index;
318 guint32 stsc_sample_index;
319 guint64 chunk_offset;
322 guint32 stts_samples;
323 guint32 n_sample_times;
324 guint32 stts_sample_index;
326 guint32 stts_duration;
328 gboolean stss_present;
329 guint32 n_sample_syncs;
332 gboolean stps_present;
333 guint32 n_sample_partial_syncs;
336 gboolean ctts_present;
337 guint32 n_composition_times;
339 guint32 ctts_sample_index;
344 gboolean parsed_trex;
345 guint32 def_sample_duration;
346 guint32 def_sample_size;
347 guint32 def_sample_flags;
352 QTDEMUX_STATE_INITIAL, /* Initial state (haven't got the header yet) */
353 QTDEMUX_STATE_HEADER, /* Parsing the header */
354 QTDEMUX_STATE_MOVIE, /* Parsing/Playing the media data */
355 QTDEMUX_STATE_BUFFER_MDAT /* Buffering the mdat atom */
358 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
359 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
360 guint32 fourcc, GstByteReader * parser);
361 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
362 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
363 guint32 fourcc, GstByteReader * parser);
365 static GstStaticPadTemplate gst_qtdemux_sink_template =
366 GST_STATIC_PAD_TEMPLATE ("sink",
369 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
373 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
374 GST_STATIC_PAD_TEMPLATE ("video_%u",
377 GST_STATIC_CAPS_ANY);
379 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
380 GST_STATIC_PAD_TEMPLATE ("audio_%u",
383 GST_STATIC_CAPS_ANY);
385 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
386 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
389 GST_STATIC_CAPS_ANY);
391 #define gst_qtdemux_parent_class parent_class
392 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
394 static void gst_qtdemux_dispose (GObject * object);
397 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
400 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
401 QtDemuxStream * str, gint64 media_offset);
404 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
405 static GstIndex *gst_qtdemux_get_index (GstElement * element);
407 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
408 GstStateChange transition);
409 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
410 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
411 GstObject * parent, GstPadMode mode, gboolean active);
413 static void gst_qtdemux_loop (GstPad * pad);
414 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
416 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
418 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
419 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
420 QtDemuxStream * stream);
422 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
423 const guint8 * buffer, guint length);
424 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
425 const guint8 * buffer, guint length);
426 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
428 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
429 QtDemuxStream * stream, GNode * esds, GstTagList * list);
430 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
431 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
432 gchar ** codec_name);
433 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
434 QtDemuxStream * stream, guint32 fourcc, const guint8 * data, int len,
435 gchar ** codec_name);
436 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux,
437 QtDemuxStream * stream, guint32 fourcc, const guint8 * data,
438 gchar ** codec_name);
439 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
440 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
441 gchar ** codec_name);
443 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
444 QtDemuxStream * stream, guint32 n);
445 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
446 static void gst_qtdemux_stream_free (GstQTDemux * qtdemux,
447 QtDemuxStream * stream);
448 static void gst_qtdemux_stream_clear (QtDemuxStream * stream);
449 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
452 gst_qtdemux_class_init (GstQTDemuxClass * klass)
454 GObjectClass *gobject_class;
455 GstElementClass *gstelement_class;
457 gobject_class = (GObjectClass *) klass;
458 gstelement_class = (GstElementClass *) klass;
460 parent_class = g_type_class_peek_parent (klass);
462 gobject_class->dispose = gst_qtdemux_dispose;
464 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
466 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
467 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
470 gst_tag_register_musicbrainz_tags ();
472 gst_element_class_add_pad_template (gstelement_class,
473 gst_static_pad_template_get (&gst_qtdemux_sink_template));
474 gst_element_class_add_pad_template (gstelement_class,
475 gst_static_pad_template_get (&gst_qtdemux_videosrc_template));
476 gst_element_class_add_pad_template (gstelement_class,
477 gst_static_pad_template_get (&gst_qtdemux_audiosrc_template));
478 gst_element_class_add_pad_template (gstelement_class,
479 gst_static_pad_template_get (&gst_qtdemux_subsrc_template));
480 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
482 "Demultiplex a QuickTime file into audio and video streams",
483 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
485 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
490 gst_qtdemux_init (GstQTDemux * qtdemux)
493 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
494 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
495 gst_pad_set_activatemode_function (qtdemux->sinkpad,
496 qtdemux_sink_activate_mode);
497 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
498 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
499 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
501 qtdemux->state = QTDEMUX_STATE_INITIAL;
502 qtdemux->pullbased = FALSE;
503 qtdemux->posted_redirect = FALSE;
504 qtdemux->neededbytes = 16;
506 qtdemux->adapter = gst_adapter_new ();
508 qtdemux->first_mdat = -1;
509 qtdemux->got_moov = FALSE;
510 qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
511 qtdemux->mdatbuffer = NULL;
512 qtdemux->base_timestamp = GST_CLOCK_TIME_NONE;
513 qtdemux->pending_newsegment = NULL;
514 qtdemux->upstream_newsegment = FALSE;
515 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
517 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
521 gst_qtdemux_dispose (GObject * object)
523 GstQTDemux *qtdemux = GST_QTDEMUX (object);
525 if (qtdemux->adapter) {
526 g_object_unref (G_OBJECT (qtdemux->adapter));
527 qtdemux->adapter = NULL;
530 G_OBJECT_CLASS (parent_class)->dispose (object);
534 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
536 if (qtdemux->posted_redirect) {
537 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
538 (_("This file contains no playable streams.")),
539 ("no known streams found, a redirect message has been posted"));
541 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
542 (_("This file contains no playable streams.")),
543 ("no known streams found"));
548 _gst_buffer_copy_into_mem (GstBuffer * dest, gsize offset, const guint8 * src,
553 g_return_if_fail (gst_buffer_is_writable (dest));
555 bsize = gst_buffer_get_size (dest);
556 g_return_if_fail (bsize >= offset + size);
558 gst_buffer_fill (dest, offset, src, size);
562 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
566 buf = gst_buffer_new ();
567 gst_buffer_append_memory (buf,
568 gst_memory_new_wrapped (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
569 mem, size, 0, size, mem, free_func));
575 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
582 if (G_UNLIKELY (size == 0)) {
584 GstBuffer *tmp = NULL;
586 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
587 if (ret != GST_FLOW_OK)
590 gst_buffer_map (tmp, &map, GST_MAP_READ);
591 size = QT_UINT32 (map.data);
592 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
594 gst_buffer_unmap (tmp, &map);
595 gst_buffer_unref (tmp);
598 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
599 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
600 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
601 /* we're pulling header but already got most interesting bits,
602 * so never mind the rest (e.g. tags) (that much) */
603 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
607 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
608 (_("This file is invalid and cannot be played.")),
609 ("atom has bogus size %" G_GUINT64_FORMAT, size));
610 return GST_FLOW_ERROR;
614 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
616 if (G_UNLIKELY (flow != GST_FLOW_OK))
619 bsize = gst_buffer_get_size (*buf);
620 /* Catch short reads - we don't want any partial atoms */
621 if (G_UNLIKELY (bsize < size)) {
622 GST_WARNING_OBJECT (qtdemux,
623 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
624 gst_buffer_unref (*buf);
634 gst_qtdemux_src_convert (GstPad * pad, GstFormat src_format, gint64 src_value,
635 GstFormat dest_format, gint64 * dest_value)
638 QtDemuxStream *stream = gst_pad_get_element_private (pad);
639 GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
642 if (stream->subtype != FOURCC_vide) {
647 switch (src_format) {
648 case GST_FORMAT_TIME:
649 switch (dest_format) {
650 case GST_FORMAT_BYTES:{
651 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
655 *dest_value = stream->samples[index].offset;
657 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
658 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
659 GST_TIME_ARGS (src_value), *dest_value);
667 case GST_FORMAT_BYTES:
668 switch (dest_format) {
669 case GST_FORMAT_TIME:{
671 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
678 gst_util_uint64_scale (stream->samples[index].timestamp,
679 GST_SECOND, stream->timescale);
680 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Offset->Time :%"
681 G_GUINT64_FORMAT "->%" GST_TIME_FORMAT,
682 src_value, GST_TIME_ARGS (*dest_value));
695 gst_object_unref (qtdemux);
702 gst_qtdemux_get_duration (GstQTDemux * qtdemux, gint64 * duration)
706 *duration = GST_CLOCK_TIME_NONE;
708 if (qtdemux->duration != 0) {
709 if (qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
710 *duration = gst_util_uint64_scale (qtdemux->duration,
711 GST_SECOND, qtdemux->timescale);
718 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
721 gboolean res = FALSE;
722 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
724 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
726 switch (GST_QUERY_TYPE (query)) {
727 case GST_QUERY_POSITION:
728 if (GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
729 gst_query_set_position (query, GST_FORMAT_TIME,
730 qtdemux->segment.position);
734 case GST_QUERY_DURATION:{
737 gst_query_parse_duration (query, &fmt, NULL);
738 if (fmt == GST_FORMAT_TIME) {
739 /* First try to query upstream */
740 res = gst_pad_query_default (pad, parent, query);
742 gint64 duration = -1;
743 gst_qtdemux_get_duration (qtdemux, &duration);
745 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
752 case GST_QUERY_CONVERT:{
753 GstFormat src_fmt, dest_fmt;
754 gint64 src_value, dest_value = 0;
756 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
758 res = gst_qtdemux_src_convert (pad,
759 src_fmt, src_value, dest_fmt, &dest_value);
761 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
766 case GST_QUERY_FORMATS:
767 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
770 case GST_QUERY_SEEKING:{
774 /* try upstream first */
775 res = gst_pad_query_default (pad, parent, query);
778 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
779 if (fmt == GST_FORMAT_TIME) {
780 gint64 duration = -1;
782 gst_qtdemux_get_duration (qtdemux, &duration);
784 if (!qtdemux->pullbased) {
787 /* we might be able with help from upstream */
789 q = gst_query_new_seeking (GST_FORMAT_BYTES);
790 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
791 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
792 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
796 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
803 res = gst_pad_query_default (pad, parent, query);
811 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
813 if (G_LIKELY (stream->pad)) {
814 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
815 GST_DEBUG_PAD_NAME (stream->pad));
817 if (G_UNLIKELY (stream->pending_tags)) {
818 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
819 stream->pending_tags);
820 gst_pad_push_event (stream->pad,
821 gst_event_new_tag (stream->pending_tags));
822 stream->pending_tags = NULL;
825 if (G_UNLIKELY (stream->send_global_tags && qtdemux->tag_list)) {
826 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
828 gst_pad_push_event (stream->pad,
829 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
830 stream->send_global_tags = FALSE;
835 /* push event on all source pads; takes ownership of the event */
837 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
840 gboolean has_valid_stream = FALSE;
841 GstEventType etype = GST_EVENT_TYPE (event);
843 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
844 GST_EVENT_TYPE_NAME (event));
846 for (n = 0; n < qtdemux->n_streams; n++) {
848 QtDemuxStream *stream = qtdemux->streams[n];
849 GST_DEBUG_OBJECT (qtdemux, "pushing on pad %i", n);
851 if ((pad = stream->pad)) {
852 has_valid_stream = TRUE;
854 if (etype == GST_EVENT_EOS) {
855 /* let's not send twice */
856 if (stream->sent_eos)
858 stream->sent_eos = TRUE;
861 gst_pad_push_event (pad, gst_event_ref (event));
865 gst_event_unref (event);
867 /* if it is EOS and there are no pads, post an error */
868 if (!has_valid_stream && etype == GST_EVENT_EOS) {
869 gst_qtdemux_post_no_playable_stream_error (qtdemux);
873 /* push a pending newsegment event, if any from the streaming thread */
875 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
877 if (qtdemux->pending_newsegment) {
878 gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
879 qtdemux->pending_newsegment = NULL;
880 qtdemux->upstream_newsegment = FALSE;
890 find_func (QtDemuxSample * s1, guint64 * media_time, gpointer user_data)
892 if (s1->timestamp > *media_time)
898 /* find the index of the sample that includes the data for @media_time using a
899 * binary search. Only to be called in optimized cases of linear search below.
901 * Returns the index of the sample.
904 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
907 QtDemuxSample *result;
910 /* convert media_time to mov format */
912 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
914 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
915 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
916 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
918 if (G_LIKELY (result))
919 index = result - str->samples;
928 /* find the index of the sample that includes the data for @media_offset using a
931 * Returns the index of the sample.
934 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
935 QtDemuxStream * str, gint64 media_offset)
937 QtDemuxSample *result = str->samples;
940 if (result == NULL || str->n_samples == 0)
943 if (media_offset == result->offset)
947 while (index < str->n_samples - 1) {
948 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
951 if (media_offset < result->offset)
962 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
967 /* find the index of the sample that includes the data for @media_time using a
968 * linear search, and keeping in mind that not all samples may have been parsed
969 * yet. If possible, it will delegate to binary search.
971 * Returns the index of the sample.
974 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
980 /* convert media_time to mov format */
982 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
984 if (mov_time == str->samples[0].timestamp)
987 /* use faster search if requested time in already parsed range */
988 if (str->stbl_index >= 0 &&
989 mov_time <= str->samples[str->stbl_index].timestamp)
990 return gst_qtdemux_find_index (qtdemux, str, media_time);
992 while (index < str->n_samples - 1) {
993 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
996 if (mov_time < str->samples[index + 1].timestamp)
1006 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1011 /* find the index of the keyframe needed to decode the sample at @index
1014 * Returns the index of the keyframe.
1017 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1020 guint32 new_index = index;
1022 if (index >= str->n_samples) {
1023 new_index = str->n_samples;
1027 /* all keyframes, return index */
1028 if (str->all_keyframe) {
1033 /* else go back until we have a keyframe */
1035 if (str->samples[new_index].keyframe)
1045 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index before index %u "
1046 "gave %u", index, new_index);
1051 /* find the segment for @time_position for @stream
1053 * Returns -1 if the segment cannot be found.
1056 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1057 guint64 time_position)
1062 GST_LOG_OBJECT (qtdemux, "finding segment for %" GST_TIME_FORMAT,
1063 GST_TIME_ARGS (time_position));
1065 /* find segment corresponding to time_position if we are looking
1068 for (i = 0; i < stream->n_segments; i++) {
1069 QtDemuxSegment *segment = &stream->segments[i];
1071 GST_LOG_OBJECT (qtdemux,
1072 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1073 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1075 /* For the last segment we include stop_time in the last segment */
1076 if (i < stream->n_segments - 1) {
1077 if (segment->time <= time_position && time_position < segment->stop_time) {
1078 GST_LOG_OBJECT (qtdemux, "segment %d matches", i);
1083 if (segment->time <= time_position && time_position <= segment->stop_time) {
1084 GST_LOG_OBJECT (qtdemux, "segment %d matches", i);
1093 /* move the stream @str to the sample position @index.
1095 * Updates @str->sample_index and marks discontinuity if needed.
1098 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1101 /* no change needed */
1102 if (index == str->sample_index)
1105 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1108 /* position changed, we have a discont */
1109 str->sample_index = index;
1110 str->offset_in_sample = 0;
1111 /* Each time we move in the stream we store the position where we are
1113 str->from_sample = index;
1114 str->discont = TRUE;
1118 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1119 gint64 * key_time, gint64 * key_offset)
1122 gint64 min_byte_offset = -1;
1125 min_offset = desired_time;
1127 /* for each stream, find the index of the sample in the segment
1128 * and move back to the previous keyframe. */
1129 for (n = 0; n < qtdemux->n_streams; n++) {
1131 guint32 index, kindex;
1133 guint64 media_start;
1136 QtDemuxSegment *seg;
1138 str = qtdemux->streams[n];
1140 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1141 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1143 /* segment not found, continue with normal flow */
1147 /* get segment and time in the segment */
1148 seg = &str->segments[seg_idx];
1149 seg_time = desired_time - seg->time;
1151 /* get the media time in the segment */
1152 media_start = seg->media_start + seg_time;
1154 /* get the index of the sample with media time */
1155 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1156 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1157 " at offset %" G_GUINT64_FORMAT,
1158 GST_TIME_ARGS (media_start), index, str->samples[index].offset);
1160 /* find previous keyframe */
1161 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index);
1163 /* if the keyframe is at a different position, we need to update the
1164 * requested seek time */
1165 if (index != kindex) {
1168 /* get timestamp of keyframe */
1170 gst_util_uint64_scale (str->samples[kindex].timestamp, GST_SECOND,
1172 GST_DEBUG_OBJECT (qtdemux, "keyframe at %u with time %" GST_TIME_FORMAT
1173 " at offset %" G_GUINT64_FORMAT,
1174 kindex, GST_TIME_ARGS (media_time), str->samples[kindex].offset);
1176 /* keyframes in the segment get a chance to change the
1177 * desired_offset. keyframes out of the segment are
1179 if (media_time >= seg->media_start) {
1182 /* this keyframe is inside the segment, convert back to
1184 seg_time = (media_time - seg->media_start) + seg->time;
1185 if (seg_time < min_offset)
1186 min_offset = seg_time;
1190 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1191 min_byte_offset = str->samples[index].offset;
1195 *key_time = min_offset;
1197 *key_offset = min_byte_offset;
1201 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1202 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1206 g_return_val_if_fail (format != NULL, FALSE);
1207 g_return_val_if_fail (cur != NULL, FALSE);
1208 g_return_val_if_fail (stop != NULL, FALSE);
1210 if (*format == GST_FORMAT_TIME)
1214 if (cur_type != GST_SEEK_TYPE_NONE)
1215 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1216 if (res && stop_type != GST_SEEK_TYPE_NONE)
1217 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1220 *format = GST_FORMAT_TIME;
1225 /* perform seek in push based mode:
1226 find BYTE position to move to based on time and delegate to upstream
1229 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1234 GstSeekType cur_type, stop_type;
1239 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1241 gst_event_parse_seek (event, &rate, &format, &flags,
1242 &cur_type, &cur, &stop_type, &stop);
1244 /* FIXME, always play to the end */
1247 /* only forward streaming and seeking is possible */
1249 goto unsupported_seek;
1251 /* convert to TIME if needed and possible */
1252 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1256 /* find reasonable corresponding BYTE position,
1257 * also try to mind about keyframes, since we can not go back a bit for them
1259 gst_qtdemux_adjust_seek (qtdemux, cur, NULL, &byte_cur);
1264 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1265 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1268 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1269 GST_DEBUG_OBJECT (qtdemux,
1270 "Requested seek time: %" GST_TIME_FORMAT ", calculated seek offset: %"
1271 G_GUINT64_FORMAT, GST_TIME_ARGS (cur), byte_cur);
1272 GST_OBJECT_LOCK (qtdemux);
1273 qtdemux->requested_seek_time = cur;
1274 qtdemux->seek_offset = byte_cur;
1275 GST_OBJECT_UNLOCK (qtdemux);
1278 /* BYTE seek event */
1279 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1281 res = gst_pad_push_event (qtdemux->sinkpad, event);
1288 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1294 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1299 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1304 /* perform the seek.
1306 * We set all segment_indexes in the streams to unknown and
1307 * adjust the time_position to the desired position. this is enough
1308 * to trigger a segment switch in the streaming thread to start
1309 * streaming from the desired position.
1311 * Keyframe seeking is a little more complicated when dealing with
1312 * segments. Ideally we want to move to the previous keyframe in
1313 * the segment but there might not be a keyframe in the segment. In
1314 * fact, none of the segments could contain a keyframe. We take a
1315 * practical approach: seek to the previous keyframe in the segment,
1316 * if there is none, seek to the beginning of the segment.
1318 * Called with STREAM_LOCK
1321 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment)
1323 gint64 desired_offset;
1326 desired_offset = segment->position;
1328 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1329 GST_TIME_ARGS (desired_offset));
1331 /* may not have enough fragmented info to do this adjustment,
1332 * and we can't scan (and probably should not) at this time with
1333 * possibly flushing upstream */
1334 if ((segment->flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1337 gst_qtdemux_adjust_seek (qtdemux, desired_offset, &min_offset, NULL);
1338 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1339 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1340 desired_offset = min_offset;
1343 /* and set all streams to the final position */
1344 for (n = 0; n < qtdemux->n_streams; n++) {
1345 QtDemuxStream *stream = qtdemux->streams[n];
1347 stream->time_position = desired_offset;
1348 stream->sample_index = -1;
1349 stream->offset_in_sample = 0;
1350 stream->segment_index = -1;
1351 stream->last_ret = GST_FLOW_OK;
1352 stream->sent_eos = FALSE;
1354 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1355 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1357 segment->position = desired_offset;
1358 segment->time = desired_offset;
1360 /* we stop at the end */
1361 if (segment->stop == -1)
1362 segment->stop = segment->duration;
1367 /* do a seek in pull based mode */
1369 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1374 GstSeekType cur_type, stop_type;
1378 GstSegment seeksegment;
1382 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1384 gst_event_parse_seek (event, &rate, &format, &flags,
1385 &cur_type, &cur, &stop_type, &stop);
1387 /* we have to have a format as the segment format. Try to convert
1389 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1393 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1395 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1399 flush = flags & GST_SEEK_FLAG_FLUSH;
1401 /* stop streaming, either by flushing or by pausing the task */
1403 /* unlock upstream pull_range */
1404 gst_pad_push_event (qtdemux->sinkpad, gst_event_new_flush_start ());
1405 /* make sure out loop function exits */
1406 gst_qtdemux_push_event (qtdemux, gst_event_new_flush_start ());
1408 /* non flushing seek, pause the task */
1409 gst_pad_pause_task (qtdemux->sinkpad);
1412 /* wait for streaming to finish */
1413 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1415 /* copy segment, we need this because we still need the old
1416 * segment when we close the current segment. */
1417 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1420 /* configure the segment with the seek variables */
1421 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1422 gst_segment_do_seek (&seeksegment, rate, format, flags,
1423 cur_type, cur, stop_type, stop, &update);
1426 /* now do the seek, this actually never returns FALSE */
1427 gst_qtdemux_perform_seek (qtdemux, &seeksegment);
1429 /* prepare for streaming again */
1431 gst_pad_push_event (qtdemux->sinkpad, gst_event_new_flush_stop (TRUE));
1432 gst_qtdemux_push_event (qtdemux, gst_event_new_flush_stop (TRUE));
1435 /* commit the new segment */
1436 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1438 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1439 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
1440 gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1441 qtdemux->segment.format, qtdemux->segment.position));
1444 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1445 for (i = 0; i < qtdemux->n_streams; i++)
1446 qtdemux->streams[i]->last_ret = GST_FLOW_OK;
1448 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1449 qtdemux->sinkpad, NULL);
1451 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1458 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1464 qtdemux_ensure_index (GstQTDemux * qtdemux)
1468 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1470 /* Build complete index */
1471 for (i = 0; i < qtdemux->n_streams; i++) {
1472 QtDemuxStream *stream = qtdemux->streams[i];
1474 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1482 GST_LOG_OBJECT (qtdemux,
1483 "Building complete index of stream %u for seeking failed!", i);
1489 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1492 gboolean res = TRUE;
1493 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1495 switch (GST_EVENT_TYPE (event)) {
1496 case GST_EVENT_SEEK:
1498 #ifndef GST_DISABLE_GST_DEBUG
1499 GstClockTime ts = gst_util_get_timestamp ();
1502 if (qtdemux->mss_mode || qtdemux->fragmented) {
1503 /* seek should be handled by upstream, we might need to re-download fragments */
1504 GST_DEBUG_OBJECT (qtdemux,
1505 "leting upstream handle seek for smoothstreaming");
1509 /* Build complete index for seeking;
1510 * if not a fragmented file at least */
1511 if (!qtdemux->fragmented)
1512 if (!qtdemux_ensure_index (qtdemux))
1514 #ifndef GST_DISABLE_GST_DEBUG
1515 ts = gst_util_get_timestamp () - ts;
1516 GST_INFO_OBJECT (qtdemux,
1517 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1520 if (qtdemux->pullbased) {
1521 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1522 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1523 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1525 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams
1526 && !qtdemux->fragmented) {
1527 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1529 GST_DEBUG_OBJECT (qtdemux,
1530 "ignoring seek in push mode in current state");
1533 gst_event_unref (event);
1536 case GST_EVENT_NAVIGATION:
1538 gst_event_unref (event);
1542 res = gst_pad_event_default (pad, parent, event);
1552 GST_ERROR_OBJECT (qtdemux, "Index failed");
1553 gst_event_unref (event);
1559 /* stream/index return sample that is min/max w.r.t. byte position,
1560 * time is min/max w.r.t. time of samples,
1561 * the latter need not be time of the former sample */
1563 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1564 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1567 gint64 time, min_time;
1568 QtDemuxStream *stream;
1574 for (n = 0; n < qtdemux->n_streams; ++n) {
1577 gboolean set_sample;
1579 str = qtdemux->streams[n];
1586 i = str->n_samples - 1;
1589 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1590 if (str->samples[i].size &&
1591 ((fw && (str->samples[i].offset >= byte_pos)) ||
1593 (str->samples[i].offset + str->samples[i].size <=
1595 /* move stream to first available sample */
1597 gst_qtdemux_move_stream (qtdemux, str, i);
1600 /* determine min/max time */
1601 time = str->samples[i].timestamp + str->samples[i].pts_offset;
1602 time = gst_util_uint64_scale (time, GST_SECOND, str->timescale);
1603 if (min_time == -1 || (!fw && time > min_time) ||
1604 (fw && time < min_time)) {
1607 /* determine stream with leading sample, to get its position */
1609 && (str->samples[i].offset < stream->samples[index].offset))
1611 && (str->samples[i].offset > stream->samples[index].offset))) {
1618 /* no sample for this stream, mark eos */
1620 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1631 static QtDemuxStream *
1632 _create_stream (void)
1634 QtDemuxStream *stream;
1636 stream = g_new0 (QtDemuxStream, 1);
1637 /* new streams always need a discont */
1638 stream->discont = TRUE;
1639 /* we enable clipping for raw audio/video streams */
1640 stream->need_clip = FALSE;
1641 stream->need_process = FALSE;
1642 stream->segment_index = -1;
1643 stream->time_position = 0;
1644 stream->sample_index = -1;
1645 stream->offset_in_sample = 0;
1646 stream->last_ret = GST_FLOW_OK;
1651 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1653 GstStructure *structure;
1654 const gchar *variant;
1655 const GstCaps *mediacaps = NULL;
1657 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1659 structure = gst_caps_get_structure (caps, 0);
1660 variant = gst_structure_get_string (structure, "variant");
1662 if (variant && strcmp (variant, "mss-fragmented") == 0) {
1663 QtDemuxStream *stream;
1664 const GValue *value;
1666 demux->fragmented = TRUE;
1667 demux->mss_mode = TRUE;
1669 if (demux->n_streams > 1) {
1670 /* can't do this, we can only renegotiate for another mss format */
1674 value = gst_structure_get_value (structure, "media-caps");
1677 const GValue *timescale_v;
1679 /* TODO update when stream changes during playback */
1681 if (demux->n_streams == 0) {
1682 stream = _create_stream ();
1683 demux->streams[demux->n_streams] = stream;
1684 demux->n_streams = 1;
1686 stream = demux->streams[0];
1689 timescale_v = gst_structure_get_value (structure, "timescale");
1691 stream->timescale = g_value_get_uint64 (timescale_v);
1693 /* default mss timescale */
1694 stream->timescale = 10000000;
1696 demux->timescale = stream->timescale;
1698 mediacaps = gst_value_get_caps (value);
1699 if (!stream->caps || !gst_caps_is_equal_fixed (mediacaps, stream->caps)) {
1700 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1703 gst_caps_replace (&stream->caps, (GstCaps *) mediacaps);
1704 structure = gst_caps_get_structure (mediacaps, 0);
1705 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
1706 stream->subtype = FOURCC_vide;
1708 gst_structure_get_int (structure, "width", &stream->width);
1709 gst_structure_get_int (structure, "height", &stream->height);
1710 gst_structure_get_fraction (structure, "framerate", &stream->fps_n,
1712 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
1714 stream->subtype = FOURCC_soun;
1715 gst_structure_get_int (structure, "channels", &stream->n_channels);
1716 gst_structure_get_int (structure, "rate", &rate);
1717 stream->rate = rate;
1720 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
1727 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
1731 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
1732 gst_pad_stop_task (qtdemux->sinkpad);
1734 if (hard || qtdemux->mss_mode) {
1735 qtdemux->state = QTDEMUX_STATE_INITIAL;
1736 qtdemux->neededbytes = 16;
1737 qtdemux->todrop = 0;
1738 qtdemux->pullbased = FALSE;
1739 qtdemux->posted_redirect = FALSE;
1740 qtdemux->first_mdat = -1;
1741 qtdemux->header_size = 0;
1742 qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
1743 if (qtdemux->mdatbuffer)
1744 gst_buffer_unref (qtdemux->mdatbuffer);
1745 qtdemux->mdatbuffer = NULL;
1746 qtdemux->mdatleft = 0;
1747 if (qtdemux->comp_brands)
1748 gst_buffer_unref (qtdemux->comp_brands);
1749 qtdemux->comp_brands = NULL;
1750 if (qtdemux->moov_node)
1751 g_node_destroy (qtdemux->moov_node);
1752 qtdemux->moov_node = NULL;
1753 qtdemux->moov_node_compressed = NULL;
1754 if (qtdemux->tag_list)
1755 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
1756 qtdemux->tag_list = NULL;
1758 if (qtdemux->element_index)
1759 gst_object_unref (qtdemux->element_index);
1760 qtdemux->element_index = NULL;
1763 qtdemux->offset = 0;
1764 gst_adapter_clear (qtdemux->adapter);
1767 for (n = 0; n < qtdemux->n_streams; n++) {
1768 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
1769 qtdemux->streams[n] = NULL;
1771 qtdemux->n_streams = 0;
1772 qtdemux->n_video_streams = 0;
1773 qtdemux->n_audio_streams = 0;
1774 qtdemux->n_sub_streams = 0;
1775 qtdemux->exposed = FALSE;
1776 qtdemux->fragmented = FALSE;
1777 qtdemux->mss_mode = FALSE;
1778 gst_caps_replace (&qtdemux->media_caps, NULL);
1779 qtdemux->timescale = 0;
1780 qtdemux->got_moov = FALSE;
1781 } else if (qtdemux->mss_mode) {
1782 for (n = 0; n < qtdemux->n_streams; n++)
1783 gst_qtdemux_stream_clear (qtdemux->streams[n]);
1785 for (n = 0; n < qtdemux->n_streams; n++) {
1786 qtdemux->streams[n]->last_ret = GST_FLOW_OK;
1787 qtdemux->streams[n]->sent_eos = FALSE;
1791 if (hard || qtdemux->mss_mode) {
1792 qtdemux->major_brand = 0;
1793 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
1794 if (qtdemux->pending_newsegment)
1795 gst_object_unref (qtdemux->pending_newsegment);
1796 qtdemux->pending_newsegment = NULL;
1797 qtdemux->upstream_newsegment = TRUE;
1798 qtdemux->requested_seek_time = GST_CLOCK_TIME_NONE;
1799 qtdemux->seek_offset = 0;
1800 qtdemux->upstream_seekable = FALSE;
1801 qtdemux->upstream_size = 0;
1803 qtdemux->base_timestamp = GST_CLOCK_TIME_NONE;
1804 qtdemux->duration = 0;
1805 qtdemux->mfra_offset = 0;
1806 qtdemux->moof_offset = 0;
1811 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
1814 GstQTDemux *demux = GST_QTDEMUX (parent);
1817 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
1819 switch (GST_EVENT_TYPE (event)) {
1820 case GST_EVENT_SEGMENT:
1823 QtDemuxStream *stream;
1827 /* some debug output */
1828 gst_event_copy_segment (event, &segment);
1829 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
1832 gst_event_replace (&demux->pending_newsegment, event);
1833 demux->upstream_newsegment = TRUE;
1835 /* chain will send initial newsegment after pads have been added */
1836 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
1837 if (!demux->mss_mode) {
1838 GST_DEBUG_OBJECT (demux, "still starting, eating event");
1843 /* we only expect a BYTE segment, e.g. following a seek */
1844 if (segment.format == GST_FORMAT_BYTES) {
1845 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
1846 gint64 requested_seek_time;
1847 guint64 seek_offset;
1849 offset = segment.start;
1851 GST_OBJECT_LOCK (demux);
1852 requested_seek_time = demux->requested_seek_time;
1853 seek_offset = demux->seek_offset;
1854 demux->requested_seek_time = -1;
1855 demux->seek_offset = -1;
1856 GST_OBJECT_UNLOCK (demux);
1858 if (offset == seek_offset) {
1859 segment.start = requested_seek_time;
1861 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
1862 NULL, (gint64 *) & segment.start);
1863 if ((gint64) segment.start < 0)
1867 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
1868 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
1869 NULL, (gint64 *) & segment.stop);
1870 /* keyframe seeking should already arrange for start >= stop,
1871 * but make sure in other rare cases */
1872 segment.stop = MAX (segment.stop, segment.start);
1874 } else if (segment.format == GST_FORMAT_TIME) {
1877 gst_qtdemux_push_event (demux, gst_event_ref (event));
1878 gst_event_new_new_segment_full (segment.update, segment.rate,
1879 segment.arate, GST_FORMAT_TIME, segment.start, segment.stop,
1881 gst_adapter_clear (demux->adapter);
1882 demux->neededbytes = 16;
1886 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
1890 /* accept upstream's notion of segment and distribute along */
1891 segment.format = GST_FORMAT_TIME;
1892 segment.position = segment.time = segment.start;
1893 segment.duration = demux->segment.duration;
1894 segment.base = gst_segment_to_running_time (&demux->segment,
1895 GST_FORMAT_TIME, demux->segment.position);
1897 gst_segment_copy_into (&segment, &demux->segment);
1898 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
1899 gst_qtdemux_push_event (demux, gst_event_new_segment (&segment));
1901 /* clear leftover in current segment, if any */
1902 gst_adapter_clear (demux->adapter);
1903 /* set up streaming thread */
1904 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx, NULL);
1905 demux->offset = offset;
1907 demux->todrop = stream->samples[idx].offset - offset;
1908 demux->neededbytes = demux->todrop + stream->samples[idx].size;
1910 /* set up for EOS */
1911 demux->neededbytes = -1;
1915 gst_event_unref (event);
1920 case GST_EVENT_FLUSH_STOP:
1922 gst_qtdemux_reset (demux, FALSE);
1926 /* If we are in push mode, and get an EOS before we've seen any streams,
1927 * then error out - we have nowhere to send the EOS */
1928 if (!demux->pullbased) {
1930 gboolean has_valid_stream = FALSE;
1931 for (i = 0; i < demux->n_streams; i++) {
1932 if (demux->streams[i]->pad != NULL) {
1933 has_valid_stream = TRUE;
1937 if (!has_valid_stream)
1938 gst_qtdemux_post_no_playable_stream_error (demux);
1941 case GST_EVENT_CAPS:{
1942 GstCaps *caps = NULL;
1944 gst_event_parse_caps (event, &caps);
1945 gst_qtdemux_setcaps (demux, caps);
1947 gst_event_unref (event);
1955 res = gst_pad_event_default (demux->sinkpad, parent, event);
1963 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
1965 GstQTDemux *demux = GST_QTDEMUX (element);
1967 GST_OBJECT_LOCK (demux);
1968 if (demux->element_index)
1969 gst_object_unref (demux->element_index);
1971 demux->element_index = gst_object_ref (index);
1973 demux->element_index = NULL;
1975 GST_OBJECT_UNLOCK (demux);
1976 /* object lock might be taken again */
1978 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
1979 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
1980 demux->element_index, demux->index_id);
1984 gst_qtdemux_get_index (GstElement * element)
1986 GstIndex *result = NULL;
1987 GstQTDemux *demux = GST_QTDEMUX (element);
1989 GST_OBJECT_LOCK (demux);
1990 if (demux->element_index)
1991 result = gst_object_ref (demux->element_index);
1992 GST_OBJECT_UNLOCK (demux);
1994 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2001 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2003 g_free ((gpointer) stream->stco.data);
2004 stream->stco.data = NULL;
2005 g_free ((gpointer) stream->stsz.data);
2006 stream->stsz.data = NULL;
2007 g_free ((gpointer) stream->stsc.data);
2008 stream->stsc.data = NULL;
2009 g_free ((gpointer) stream->stts.data);
2010 stream->stts.data = NULL;
2011 g_free ((gpointer) stream->stss.data);
2012 stream->stss.data = NULL;
2013 g_free ((gpointer) stream->stps.data);
2014 stream->stps.data = NULL;
2015 g_free ((gpointer) stream->ctts.data);
2016 stream->ctts.data = NULL;
2020 gst_qtdemux_stream_clear (QtDemuxStream * stream)
2022 if (stream->allocator)
2023 gst_object_unref (stream->allocator);
2024 while (stream->buffers) {
2025 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2026 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2028 g_free (stream->samples);
2029 stream->samples = NULL;
2030 g_free (stream->segments);
2031 stream->segments = NULL;
2032 if (stream->pending_tags)
2033 gst_tag_list_unref (stream->pending_tags);
2034 stream->pending_tags = NULL;
2035 g_free (stream->redirect_uri);
2036 stream->redirect_uri = NULL;
2037 /* free stbl sub-atoms */
2038 gst_qtdemux_stbl_free (stream);
2040 stream->last_ret = GST_FLOW_OK;
2041 stream->sent_eos = FALSE;
2042 stream->segment_index = -1;
2043 stream->time_position = 0;
2044 stream->sample_index = -1;
2045 stream->stbl_index = -1;
2046 stream->n_samples = 0;
2050 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
2052 gst_qtdemux_stream_clear (stream);
2054 gst_caps_unref (stream->caps);
2055 stream->caps = NULL;
2057 gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
2061 static GstStateChangeReturn
2062 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2064 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2065 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2067 switch (transition) {
2068 case GST_STATE_CHANGE_PAUSED_TO_READY:
2074 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2076 switch (transition) {
2077 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2078 gst_qtdemux_reset (qtdemux, TRUE);
2089 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2091 /* counts as header data */
2092 qtdemux->header_size += length;
2094 /* only consider at least a sufficiently complete ftyp atom */
2098 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2099 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2100 GST_FOURCC_ARGS (qtdemux->major_brand));
2101 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2102 _gst_buffer_copy_into_mem (buf, 0, buffer + 16, length - 16);
2107 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist)
2109 /* Strip out bogus fields */
2111 gst_tag_list_remove_tag (taglist, GST_TAG_VIDEO_CODEC);
2113 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, taglist);
2115 if (qtdemux->tag_list) {
2116 /* prioritize native tags using _KEEP mode */
2117 gst_tag_list_insert (qtdemux->tag_list, taglist, GST_TAG_MERGE_KEEP);
2118 gst_tag_list_unref (taglist);
2120 qtdemux->tag_list = taglist;
2125 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2127 static guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2128 0x97, 0xA9, 0x42, 0xE8,
2129 0x9C, 0x71, 0x99, 0x94,
2130 0x91, 0xE3, 0xAF, 0xAC
2134 /* counts as header data */
2135 qtdemux->header_size += length;
2137 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2139 if (length <= offset + 16) {
2140 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2144 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2146 GstTagList *taglist;
2148 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2149 length - offset - 16, NULL);
2150 taglist = gst_tag_list_from_xmp_buffer (buf);
2151 gst_buffer_unref (buf);
2153 qtdemux_handle_xmp_taglist (qtdemux, taglist);
2156 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid");
2160 /* caller verifies at least 8 bytes in buf */
2162 extract_initial_length_and_fourcc (const guint8 * data, guint size,
2163 guint64 * plength, guint32 * pfourcc)
2168 length = QT_UINT32 (data);
2169 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2170 fourcc = QT_FOURCC (data + 4);
2171 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
2174 length = G_MAXUINT32;
2175 } else if (length == 1 && size >= 16) {
2176 /* this means we have an extended size, which is the 64 bit value of
2177 * the next 8 bytes */
2178 length = QT_UINT64 (data + 8);
2179 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2189 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
2191 guint32 version = 0;
2192 guint64 duration = 0;
2194 if (!gst_byte_reader_get_uint32_be (br, &version))
2199 if (!gst_byte_reader_get_uint64_be (br, &duration))
2204 if (!gst_byte_reader_get_uint32_be (br, &dur))
2209 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
2210 qtdemux->duration = duration;
2216 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
2222 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
2223 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
2225 if (!stream->parsed_trex && qtdemux->moov_node) {
2227 GstByteReader trex_data;
2229 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
2231 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
2234 guint32 id = 0, dur = 0, size = 0, flags = 0;
2236 /* skip version/flags */
2237 if (!gst_byte_reader_skip (&trex_data, 4))
2239 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
2241 if (id != stream->track_id)
2243 /* sample description index; ignore */
2244 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2246 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2248 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
2250 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
2253 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
2254 "duration %d, size %d, flags 0x%x", stream->track_id,
2257 stream->parsed_trex = TRUE;
2258 stream->def_sample_duration = dur;
2259 stream->def_sample_size = size;
2260 stream->def_sample_flags = flags;
2263 /* iterate all siblings */
2264 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
2270 *ds_duration = stream->def_sample_duration;
2271 *ds_size = stream->def_sample_size;
2272 *ds_size = stream->def_sample_size;
2274 /* even then, above values are better than random ... */
2275 if (G_UNLIKELY (!stream->parsed_trex)) {
2276 GST_WARNING_OBJECT (qtdemux,
2277 "failed to find fragment defaults for stream %d", stream->track_id);
2285 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
2286 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
2287 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
2288 gint64 * base_offset, gint64 * running_offset)
2291 gint32 data_offset = 0;
2292 guint32 flags = 0, first_flags = 0, samples_count = 0;
2295 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
2296 QtDemuxSample *sample;
2297 gboolean ismv = FALSE;
2299 GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
2300 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT,
2301 stream->track_id, d_sample_duration, d_sample_size, d_sample_flags,
2304 /* presence of stss or not can't really tell us much,
2305 * and flags and so on tend to be marginally reliable in these files */
2306 if (stream->subtype == FOURCC_soun) {
2307 GST_DEBUG_OBJECT (qtdemux,
2308 "sound track in fragmented file; marking all keyframes");
2309 stream->all_keyframe = TRUE;
2312 if (!gst_byte_reader_skip (trun, 1) ||
2313 !gst_byte_reader_get_uint24_be (trun, &flags))
2316 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
2319 if (flags & TR_DATA_OFFSET) {
2320 /* note this is really signed */
2321 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
2323 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
2324 /* default base offset = first byte of moof */
2325 if (*base_offset == -1) {
2326 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
2327 *base_offset = moof_offset;
2329 *running_offset = *base_offset + data_offset;
2331 /* if no offset at all, that would mean data starts at moof start,
2332 * which is a bit wrong and is ismv crappy way, so compensate
2333 * assuming data is in mdat following moof */
2334 if (*base_offset == -1) {
2335 *base_offset = moof_offset + moof_length + 8;
2336 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
2339 if (*running_offset == -1)
2340 *running_offset = *base_offset;
2343 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
2345 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
2346 data_offset, flags, samples_count);
2348 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2349 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
2350 GST_DEBUG_OBJECT (qtdemux,
2351 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
2352 flags ^= TR_FIRST_SAMPLE_FLAGS;
2354 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
2356 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
2360 /* FIXME ? spec says other bits should also be checked to determine
2361 * entry size (and prefix size for that matter) */
2363 dur_offset = size_offset = 0;
2364 if (flags & TR_SAMPLE_DURATION) {
2365 GST_LOG_OBJECT (qtdemux, "entry duration present");
2366 dur_offset = entry_size;
2369 if (flags & TR_SAMPLE_SIZE) {
2370 GST_LOG_OBJECT (qtdemux, "entry size present");
2371 size_offset = entry_size;
2374 if (flags & TR_SAMPLE_FLAGS) {
2375 GST_LOG_OBJECT (qtdemux, "entry flags present");
2376 flags_offset = entry_size;
2379 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2380 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
2381 ct_offset = entry_size;
2385 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
2387 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
2389 if (stream->n_samples >=
2390 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
2393 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
2394 stream->n_samples, (guint) sizeof (QtDemuxSample),
2395 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
2397 /* create a new array of samples if it's the first sample parsed */
2398 if (stream->n_samples == 0)
2399 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
2400 /* or try to reallocate it with space enough to insert the new samples */
2402 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
2403 stream->n_samples + samples_count);
2404 if (stream->samples == NULL)
2407 if (GST_CLOCK_TIME_IS_VALID (qtdemux->base_timestamp)) {
2408 timestamp = gst_util_uint64_scale_int (qtdemux->base_timestamp,
2409 stream->timescale, GST_SECOND);
2410 qtdemux->base_timestamp = GST_CLOCK_TIME_NONE;
2412 if (G_UNLIKELY (stream->n_samples == 0)) {
2413 /* the timestamp of the first sample is also provided by the tfra entry
2414 * but we shouldn't rely on it as it is at the end of files */
2417 /* subsequent fragments extend stream */
2419 stream->samples[stream->n_samples - 1].timestamp +
2420 stream->samples[stream->n_samples - 1].duration;
2423 sample = stream->samples + stream->n_samples;
2424 for (i = 0; i < samples_count; i++) {
2425 guint32 dur, size, sflags, ct;
2427 /* first read sample data */
2428 if (flags & TR_SAMPLE_DURATION) {
2429 dur = QT_UINT32 (data + dur_offset);
2431 dur = d_sample_duration;
2433 if (flags & TR_SAMPLE_SIZE) {
2434 size = QT_UINT32 (data + size_offset);
2436 size = d_sample_size;
2438 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2440 sflags = first_flags;
2442 sflags = d_sample_flags;
2444 } else if (flags & TR_SAMPLE_FLAGS) {
2445 sflags = QT_UINT32 (data + flags_offset);
2447 sflags = d_sample_flags;
2449 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2450 ct = QT_UINT32 (data + ct_offset);
2456 /* fill the sample information */
2457 sample->offset = *running_offset;
2458 sample->pts_offset = ct;
2459 sample->size = size;
2460 sample->timestamp = timestamp;
2461 sample->duration = dur;
2462 /* sample-is-difference-sample */
2463 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
2464 * now idea how it relates to bitfield other than massive LE/BE confusion */
2465 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
2466 *running_offset += size;
2471 stream->n_samples += samples_count;
2477 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
2482 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
2488 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
2489 "be larger than %uMB (broken file?)", stream->n_samples,
2490 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
2495 /* find stream with @id */
2496 static inline QtDemuxStream *
2497 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
2499 QtDemuxStream *stream;
2503 if (G_UNLIKELY (!id)) {
2504 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
2508 /* try to get it fast and simple */
2509 if (G_LIKELY (id <= qtdemux->n_streams)) {
2510 stream = qtdemux->streams[id - 1];
2511 if (G_LIKELY (stream->track_id == id))
2515 /* linear search otherwise */
2516 for (i = 0; i < qtdemux->n_streams; i++) {
2517 stream = qtdemux->streams[i];
2518 if (stream->track_id == id)
2521 if (qtdemux->mss_mode) {
2522 /* we should have only 1 stream in the end */
2523 return qtdemux->streams[0];
2530 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
2531 QtDemuxStream ** stream, guint32 * default_sample_duration,
2532 guint32 * default_sample_size, guint32 * default_sample_flags,
2533 gint64 * base_offset)
2536 guint32 track_id = 0;
2538 if (!gst_byte_reader_skip (tfhd, 1) ||
2539 !gst_byte_reader_get_uint24_be (tfhd, &flags))
2542 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
2545 *stream = qtdemux_find_stream (qtdemux, track_id);
2546 if (G_UNLIKELY (!*stream))
2547 goto unknown_stream;
2549 if (flags & TF_BASE_DATA_OFFSET)
2550 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
2553 /* obtain stream defaults */
2554 qtdemux_parse_trex (qtdemux, *stream,
2555 default_sample_duration, default_sample_size, default_sample_flags);
2557 /* FIXME: Handle TF_SAMPLE_DESCRIPTION_INDEX properly */
2558 if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
2559 if (!gst_byte_reader_skip (tfhd, 4))
2562 if (flags & TF_DEFAULT_SAMPLE_DURATION)
2563 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
2566 if (flags & TF_DEFAULT_SAMPLE_SIZE)
2567 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
2570 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
2571 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
2578 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
2583 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
2589 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
2590 guint64 * decode_time)
2592 guint32 version = 0;
2594 if (!gst_byte_reader_get_uint32_be (br, &version))
2599 if (!gst_byte_reader_get_uint64_be (br, decode_time))
2602 guint32 dec_time = 0;
2603 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
2605 *decode_time = dec_time;
2608 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
2615 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
2621 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
2622 guint64 moof_offset, QtDemuxStream * stream)
2624 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node;
2625 GstByteReader trun_data, tfhd_data, tfdt_data;
2626 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
2627 gint64 base_offset, running_offset;
2629 /* NOTE @stream ignored */
2631 moof_node = g_node_new ((guint8 *) buffer);
2632 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
2633 qtdemux_node_dump (qtdemux, moof_node);
2635 /* unknown base_offset to start with */
2636 base_offset = running_offset = -1;
2637 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
2639 /* Fragment Header node */
2641 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
2645 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
2646 &ds_size, &ds_flags, &base_offset))
2649 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
2652 guint64 decode_time = 0;
2653 GstClockTime decode_time_ts;
2655 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
2657 decode_time_ts = gst_util_uint64_scale (decode_time, GST_SECOND,
2660 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GUINT64_FORMAT
2661 " (%" GST_TIME_FORMAT ")", decode_time,
2662 GST_TIME_ARGS (decode_time_ts));
2664 /* If there is a new segment pending, update the time/position.
2665 * Don't replace if the pending newsegment is from upstream */
2666 if (qtdemux->pending_newsegment && !qtdemux->upstream_newsegment) {
2669 gst_segment_init (&segment, GST_FORMAT_TIME);
2670 gst_event_replace (&qtdemux->pending_newsegment,
2671 gst_event_new_segment (&segment));
2672 /* ref added when replaced, release the original _new one */
2673 gst_event_unref (qtdemux->pending_newsegment);
2677 if (G_UNLIKELY (!stream)) {
2678 /* we lost track of offset, we'll need to regain it,
2679 * but can delay complaining until later or avoid doing so altogether */
2683 if (G_UNLIKELY (base_offset < -1))
2685 /* Track Run node */
2687 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
2690 qtdemux_parse_trun (qtdemux, &trun_data, stream,
2691 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
2693 /* iterate all siblings */
2694 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
2697 /* if no new base_offset provided for next traf,
2698 * base is end of current traf */
2699 base_offset = running_offset;
2700 running_offset = -1;
2702 /* iterate all siblings */
2703 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
2705 g_node_destroy (moof_node);
2710 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
2715 GST_DEBUG_OBJECT (qtdemux, "lost offset");
2720 g_node_destroy (moof_node);
2721 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
2722 (_("This file is corrupt and cannot be played.")), (NULL));
2727 /* might be used if some day we actually use mfra & co
2728 * for random access to fragments,
2729 * but that will require quite some modifications and much less relying
2730 * on a sample array */
2733 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node,
2734 QtDemuxStream * stream)
2736 guint64 time = 0, moof_offset = 0;
2737 guint32 ver_flags, track_id, len, num_entries, i;
2738 guint value_size, traf_size, trun_size, sample_size;
2739 GstBuffer *buf = NULL;
2743 gst_byte_reader_init (&tfra, (guint8 *) tfra_node->data + (4 + 4),
2744 QT_UINT32 ((guint8 *) tfra_node->data) - (4 + 4));
2746 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
2749 if (!(gst_byte_reader_get_uint32_be (&tfra, &track_id) &&
2750 gst_byte_reader_get_uint32_be (&tfra, &len) &&
2751 gst_byte_reader_get_uint32_be (&tfra, &num_entries)))
2754 GST_LOG_OBJECT (qtdemux, "id %d == stream id %d ?",
2755 track_id, stream->track_id);
2756 if (track_id != stream->track_id) {
2760 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
2761 sample_size = (len & 3) + 1;
2762 trun_size = ((len & 12) >> 2) + 1;
2763 traf_size = ((len & 48) >> 4) + 1;
2765 if (num_entries == 0)
2768 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
2769 value_size + value_size + traf_size + trun_size + sample_size))
2772 for (i = 0; i < num_entries; i++) {
2773 qt_atom_parser_get_offset (&tfra, value_size, &time);
2774 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
2775 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
2776 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
2777 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
2779 GST_LOG_OBJECT (qtdemux,
2780 "fragment time: %" GST_TIME_FORMAT " moof_offset: %u",
2781 GST_TIME_ARGS (gst_util_uint64_scale (time, GST_SECOND,
2782 stream->timescale)), moof_offset);
2784 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
2785 if (ret != GST_FLOW_OK)
2787 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
2788 moof_offset, stream);
2789 gst_buffer_unref (buf);
2797 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
2798 (_("This file is corrupt and cannot be played.")), (NULL));
2803 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
2809 qtdemux_parse_mfra (GstQTDemux * qtdemux, QtDemuxStream * stream)
2812 GNode *mfra_node, *tfra_node;
2815 if (!qtdemux->mfra_offset)
2818 ret = gst_qtdemux_pull_atom (qtdemux, qtdemux->mfra_offset, 0, &buffer);
2819 if (ret != GST_FLOW_OK)
2822 mfra_node = g_node_new ((guint8 *) GST_BUFFER_DATA (buffer));
2823 qtdemux_parse_node (qtdemux, mfra_node, GST_BUFFER_DATA (buffer),
2824 GST_BUFFER_SIZE (buffer));
2826 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
2829 qtdemux_parse_tfra (qtdemux, tfra_node, stream);
2830 /* iterate all siblings */
2831 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
2833 g_node_destroy (mfra_node);
2834 gst_buffer_unref (buffer);
2840 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
2841 (_("This file is corrupt and cannot be played.")), (NULL));
2846 static GstFlowReturn
2847 qtdemux_parse_mfro (GstQTDemux * qtdemux, guint64 * mfra_offset,
2848 guint32 * mfro_size)
2850 GstFlowReturn ret = GST_FLOW_ERROR;
2851 GstBuffer *mfro = NULL;
2854 GstFormat fmt = GST_FORMAT_BYTES;
2856 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, &fmt, &len)) {
2857 GST_DEBUG_OBJECT (qtdemux, "upstream size not available; "
2858 "can not locate mfro");
2862 ret = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
2863 if (ret != GST_FLOW_OK)
2866 fourcc = QT_FOURCC (GST_BUFFER_DATA (mfro) + 4);
2867 if (fourcc != FOURCC_mfro)
2870 GST_INFO_OBJECT (qtdemux, "Found mfro atom: fragmented mp4 container");
2871 if (GST_BUFFER_SIZE (mfro) >= 16) {
2872 GST_DEBUG_OBJECT (qtdemux, "parsing 'mfro' atom");
2873 *mfro_size = QT_UINT32 (GST_BUFFER_DATA (mfro) + 12);
2874 if (*mfro_size >= len) {
2875 GST_WARNING_OBJECT (qtdemux, "mfro.size is invalid");
2876 ret = GST_FLOW_ERROR;
2879 *mfra_offset = len - *mfro_size;
2884 gst_buffer_unref (mfro);
2890 qtdemux_parse_fragmented (GstQTDemux * qtdemux)
2893 guint32 mfra_size = 0;
2894 guint64 mfra_offset = 0;
2897 qtdemux->fragmented = FALSE;
2899 /* We check here if it is a fragmented mp4 container */
2900 ret = qtdemux_parse_mfro (qtdemux, &mfra_offset, &mfra_size);
2901 if (ret == GST_FLOW_OK && mfra_size != 0 && mfra_offset != 0) {
2902 qtdemux->fragmented = TRUE;
2903 GST_DEBUG_OBJECT (qtdemux,
2904 "mfra atom expected at offset %" G_GUINT64_FORMAT, mfra_offset);
2905 qtdemux->mfra_offset = mfra_offset;
2910 static GstFlowReturn
2911 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
2915 GstBuffer *buf = NULL;
2916 GstFlowReturn ret = GST_FLOW_OK;
2917 guint64 cur_offset = qtdemux->offset;
2920 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
2921 if (G_UNLIKELY (ret != GST_FLOW_OK))
2923 gst_buffer_map (buf, &map, GST_MAP_READ);
2924 if (G_LIKELY (map.size >= 8))
2925 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
2926 gst_buffer_unmap (buf, &map);
2927 gst_buffer_unref (buf);
2929 /* maybe we already got most we needed, so only consider this eof */
2930 if (G_UNLIKELY (length == 0)) {
2931 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
2932 (_("Invalid atom size.")),
2933 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
2934 GST_FOURCC_ARGS (fourcc)));
2941 /* record for later parsing when needed */
2942 if (!qtdemux->moof_offset) {
2943 qtdemux->moof_offset = qtdemux->offset;
2952 GST_LOG_OBJECT (qtdemux,
2953 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
2954 GST_FOURCC_ARGS (fourcc), cur_offset);
2955 qtdemux->offset += length;
2960 GstBuffer *moov = NULL;
2962 if (qtdemux->got_moov) {
2963 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
2964 qtdemux->offset += length;
2968 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
2969 if (ret != GST_FLOW_OK)
2971 gst_buffer_map (moov, &map, GST_MAP_READ);
2973 if (length != map.size) {
2974 /* Some files have a 'moov' atom at the end of the file which contains
2975 * a terminal 'free' atom where the body of the atom is missing.
2976 * Check for, and permit, this special case.
2978 if (map.size >= 8) {
2979 guint8 *final_data = map.data + (map.size - 8);
2980 guint32 final_length = QT_UINT32 (final_data);
2981 guint32 final_fourcc = QT_FOURCC (final_data + 4);
2983 if (final_fourcc == FOURCC_free
2984 && map.size + final_length - 8 == length) {
2985 /* Ok, we've found that special case. Allocate a new buffer with
2986 * that free atom actually present. */
2987 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
2988 gst_buffer_fill (newmoov, 0, map.data, map.size);
2989 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
2990 gst_buffer_unmap (moov, &map);
2991 gst_buffer_unref (moov);
2993 gst_buffer_map (moov, &map, GST_MAP_READ);
2998 if (length != map.size) {
2999 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
3000 (_("This file is incomplete and cannot be played.")),
3001 ("We got less than expected (received %" G_GSIZE_FORMAT
3002 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
3003 (guint) length, cur_offset));
3004 gst_buffer_unmap (moov, &map);
3005 gst_buffer_unref (moov);
3006 ret = GST_FLOW_ERROR;
3009 qtdemux->offset += length;
3011 qtdemux_parse_moov (qtdemux, map.data, length);
3012 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
3014 qtdemux_parse_tree (qtdemux);
3015 g_node_destroy (qtdemux->moov_node);
3016 gst_buffer_unmap (moov, &map);
3017 gst_buffer_unref (moov);
3018 qtdemux->moov_node = NULL;
3019 qtdemux->got_moov = TRUE;
3025 GstBuffer *ftyp = NULL;
3027 /* extract major brand; might come in handy for ISO vs QT issues */
3028 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
3029 if (ret != GST_FLOW_OK)
3031 qtdemux->offset += length;
3032 gst_buffer_map (ftyp, &map, GST_MAP_READ);
3033 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
3034 gst_buffer_unmap (ftyp, &map);
3035 gst_buffer_unref (ftyp);
3040 GstBuffer *uuid = NULL;
3042 /* uuid are extension atoms */
3043 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
3044 if (ret != GST_FLOW_OK)
3046 qtdemux->offset += length;
3047 gst_buffer_map (uuid, &map, GST_MAP_READ);
3048 qtdemux_parse_uuid (qtdemux, map.data, map.size);
3049 gst_buffer_unmap (uuid, &map);
3050 gst_buffer_unref (uuid);
3055 GstBuffer *unknown = NULL;
3057 GST_LOG_OBJECT (qtdemux,
3058 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
3059 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
3061 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
3062 if (ret != GST_FLOW_OK)
3064 gst_buffer_map (unknown, &map, GST_MAP_READ);
3065 GST_MEMDUMP ("Unknown tag", map.data, map.size);
3066 gst_buffer_unmap (unknown, &map);
3067 gst_buffer_unref (unknown);
3068 qtdemux->offset += length;
3074 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
3075 /* digested all data, show what we have */
3076 qtdemux_prepare_streams (qtdemux);
3077 ret = qtdemux_expose_streams (qtdemux);
3079 qtdemux->state = QTDEMUX_STATE_MOVIE;
3080 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
3087 /* Seeks to the previous keyframe of the indexed stream and
3088 * aligns other streams with respect to the keyframe timestamp
3089 * of indexed stream. Only called in case of Reverse Playback
3091 static GstFlowReturn
3092 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
3095 guint32 seg_idx = 0, k_index = 0;
3096 guint32 ref_seg_idx, ref_k_index;
3097 guint64 k_pos = 0, last_stop = 0;
3098 QtDemuxSegment *seg = NULL;
3099 QtDemuxStream *ref_str = NULL;
3100 guint64 seg_media_start_mov; /* segment media start time in mov format */
3102 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
3103 * and finally align all the other streams on that timestamp with their
3104 * respective keyframes */
3105 for (n = 0; n < qtdemux->n_streams; n++) {
3106 QtDemuxStream *str = qtdemux->streams[n];
3108 seg_idx = gst_qtdemux_find_segment (qtdemux, str,
3109 qtdemux->segment.position);
3111 /* segment not found, continue with normal flow */
3115 /* No candidate yet, take that one */
3121 /* So that stream has a segment, we prefer video streams */
3122 if (str->subtype == FOURCC_vide) {
3128 if (G_UNLIKELY (!ref_str)) {
3129 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
3133 if (G_UNLIKELY (!ref_str->from_sample)) {
3134 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
3138 /* So that stream has been playing from from_sample to to_sample. We will
3139 * get the timestamp of the previous sample and search for a keyframe before
3140 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
3141 if (ref_str->subtype == FOURCC_vide) {
3142 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
3143 ref_str->from_sample - 1);
3145 if (ref_str->from_sample >= 10)
3146 k_index = ref_str->from_sample - 10;
3151 /* get current segment for that stream */
3152 seg = &ref_str->segments[ref_str->segment_index];
3153 /* convert seg->media_start to mov format time for timestamp comparison */
3154 seg_media_start_mov =
3155 gst_util_uint64_scale (seg->media_start, ref_str->timescale, GST_SECOND);
3156 /* Crawl back through segments to find the one containing this I frame */
3157 while (ref_str->samples[k_index].timestamp < seg_media_start_mov) {
3158 GST_DEBUG_OBJECT (qtdemux, "keyframe position is out of segment %u",
3159 ref_str->segment_index);
3160 if (G_UNLIKELY (!ref_str->segment_index)) {
3161 /* Reached first segment, let's consider it's EOS */
3164 ref_str->segment_index--;
3165 seg = &ref_str->segments[ref_str->segment_index];
3166 /* convert seg->media_start to mov format time for timestamp comparison */
3167 seg_media_start_mov =
3168 gst_util_uint64_scale (seg->media_start, ref_str->timescale,
3171 /* Calculate time position of the keyframe and where we should stop */
3173 (gst_util_uint64_scale (ref_str->samples[k_index].timestamp, GST_SECOND,
3174 ref_str->timescale) - seg->media_start) + seg->time;
3176 gst_util_uint64_scale (ref_str->samples[ref_str->from_sample].timestamp,
3177 GST_SECOND, ref_str->timescale);
3178 last_stop = (last_stop - seg->media_start) + seg->time;
3180 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
3181 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
3182 k_index, GST_TIME_ARGS (k_pos));
3184 /* Set last_stop with the keyframe timestamp we pushed of that stream */
3185 qtdemux->segment.position = last_stop;
3186 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
3187 GST_TIME_ARGS (last_stop));
3189 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
3190 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
3194 ref_seg_idx = ref_str->segment_index;
3195 ref_k_index = k_index;
3197 /* Align them all on this */
3198 for (n = 0; n < qtdemux->n_streams; n++) {
3200 guint64 media_start = 0, seg_time = 0;
3201 QtDemuxStream *str = qtdemux->streams[n];
3203 /* aligning reference stream again might lead to backing up to yet another
3204 * keyframe (due to timestamp rounding issues),
3205 * potentially putting more load on downstream; so let's try to avoid */
3206 if (str == ref_str) {
3207 seg_idx = ref_seg_idx;
3208 seg = &str->segments[seg_idx];
3209 k_index = ref_k_index;
3210 GST_DEBUG_OBJECT (qtdemux, "reference stream segment %d, "
3211 "sample at index %d", ref_str->segment_index, k_index);
3213 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
3214 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
3216 /* segment not found, continue with normal flow */
3220 /* get segment and time in the segment */
3221 seg = &str->segments[seg_idx];
3222 seg_time = k_pos - seg->time;
3224 /* get the media time in the segment */
3225 media_start = seg->media_start + seg_time;
3227 /* get the index of the sample with media time */
3228 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
3229 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u",
3230 GST_TIME_ARGS (media_start), index);
3232 /* find previous keyframe */
3233 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index);
3236 /* Remember until where we want to go */
3237 str->to_sample = str->from_sample - 1;
3238 /* Define our time position */
3239 str->time_position =
3240 (gst_util_uint64_scale (str->samples[k_index].timestamp, GST_SECOND,
3241 str->timescale) - seg->media_start) + seg->time;
3242 /* Now seek back in time */
3243 gst_qtdemux_move_stream (qtdemux, str, k_index);
3244 GST_DEBUG_OBJECT (qtdemux, "keyframe at %u, time position %"
3245 GST_TIME_FORMAT " playing from sample %u to %u", k_index,
3246 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
3252 return GST_FLOW_EOS;
3255 /* activate the given segment number @seg_idx of @stream at time @offset.
3256 * @offset is an absolute global position over all the segments.
3258 * This will push out a NEWSEGMENT event with the right values and
3259 * position the stream index to the first decodable sample before
3263 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
3264 guint32 seg_idx, guint64 offset)
3267 QtDemuxSegment *segment;
3268 guint32 index, kf_index;
3270 guint64 start, stop, time;
3273 GST_LOG_OBJECT (qtdemux, "activate segment %d, offset %" G_GUINT64_FORMAT,
3276 /* update the current segment */
3277 stream->segment_index = seg_idx;
3279 /* get the segment */
3280 segment = &stream->segments[seg_idx];
3282 if (G_UNLIKELY (offset < segment->time)) {
3283 GST_WARNING_OBJECT (qtdemux, "offset < segment->time %" G_GUINT64_FORMAT,
3288 /* segment lies beyond total indicated duration */
3289 if (G_UNLIKELY (qtdemux->segment.duration != -1 &&
3290 segment->time > qtdemux->segment.duration)) {
3291 GST_WARNING_OBJECT (qtdemux, "file duration %" G_GINT64_FORMAT
3292 " < segment->time %" G_GUINT64_FORMAT, qtdemux->segment.duration,
3297 /* get time in this segment */
3298 seg_time = offset - segment->time;
3300 GST_LOG_OBJECT (qtdemux, "seg_time %" GST_TIME_FORMAT,
3301 GST_TIME_ARGS (seg_time));
3303 if (G_UNLIKELY (seg_time > segment->duration)) {
3304 GST_LOG_OBJECT (qtdemux, "seg_time > segment->duration %" GST_TIME_FORMAT,
3305 GST_TIME_ARGS (segment->duration));
3309 /* qtdemux->segment.stop is in outside-time-realm, whereas
3310 * segment->media_stop is in track-time-realm.
3312 * In order to compare the two, we need to bring segment.stop
3313 * into the track-time-realm */
3315 stop = qtdemux->segment.stop;
3317 stop = qtdemux->segment.duration;
3319 stop = segment->media_stop;
3322 MIN (segment->media_stop, stop - segment->time + segment->media_start);
3324 if (qtdemux->segment.rate >= 0) {
3325 start = MIN (segment->media_start + seg_time, stop);
3328 if (segment->media_start >= qtdemux->segment.start) {
3329 start = segment->media_start;
3330 time = segment->time;
3332 start = qtdemux->segment.start;
3333 time = segment->time + (qtdemux->segment.start - segment->media_start);
3336 start = MAX (segment->media_start, qtdemux->segment.start);
3337 stop = MIN (segment->media_start + seg_time, stop);
3340 GST_DEBUG_OBJECT (qtdemux, "newsegment %d from %" GST_TIME_FORMAT
3341 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
3342 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
3344 /* combine global rate with that of the segment */
3345 rate = segment->rate * qtdemux->segment.rate;
3347 /* update the segment values used for clipping */
3348 /* accumulate previous segments */
3349 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
3350 stream->segment.base += (stream->segment.stop - stream->segment.start) /
3351 ABS (stream->segment.rate);
3352 stream->segment.rate = rate;
3353 stream->segment.start = start;
3354 stream->segment.stop = stop;
3355 stream->segment.time = time;
3356 stream->segment.position = start;
3358 /* now prepare and send the segment */
3360 event = gst_event_new_segment (&stream->segment);
3361 gst_pad_push_event (stream->pad, event);
3362 /* assume we can send more data now */
3363 stream->last_ret = GST_FLOW_OK;
3364 /* clear to send tags on this pad now */
3365 gst_qtdemux_push_tags (qtdemux, stream);
3368 /* and move to the keyframe before the indicated media time of the
3370 if (qtdemux->segment.rate >= 0) {
3371 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
3372 stream->to_sample = G_MAXUINT32;
3373 GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
3374 ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
3375 GST_TIME_ARGS (gst_util_uint64_scale (stream->samples[index].timestamp,
3376 GST_SECOND, stream->timescale)));
3378 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
3379 stream->to_sample = index;
3380 GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
3381 ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
3382 GST_TIME_ARGS (gst_util_uint64_scale (stream->samples[index].timestamp,
3383 GST_SECOND, stream->timescale)));
3386 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
3387 * encountered an error and printed a message so we return appropriately */
3391 /* we're at the right spot */
3392 if (index == stream->sample_index) {
3393 GST_DEBUG_OBJECT (qtdemux, "we are at the right index");
3397 /* find keyframe of the target index */
3398 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index);
3401 /* indent does stupid stuff with stream->samples[].timestamp */
3403 /* if we move forwards, we don't have to go back to the previous
3404 * keyframe since we already sent that. We can also just jump to
3405 * the keyframe right before the target index if there is one. */
3406 if (index > stream->sample_index) {
3407 /* moving forwards check if we move past a keyframe */
3408 if (kf_index > stream->sample_index) {
3409 GST_DEBUG_OBJECT (qtdemux,
3410 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT, kf_index,
3411 GST_TIME_ARGS (gst_util_uint64_scale (
3412 stream->samples[kf_index].timestamp,
3413 GST_SECOND, stream->timescale)));
3414 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
3416 GST_DEBUG_OBJECT (qtdemux,
3417 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT
3418 " already sent", kf_index,
3419 GST_TIME_ARGS (gst_util_uint64_scale (
3420 stream->samples[kf_index].timestamp,
3421 GST_SECOND, stream->timescale)));
3424 GST_DEBUG_OBJECT (qtdemux,
3425 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT, kf_index,
3426 GST_TIME_ARGS (gst_util_uint64_scale (
3427 stream->samples[kf_index].timestamp,
3428 GST_SECOND, stream->timescale)));
3429 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
3437 /* prepare to get the current sample of @stream, getting essential values.
3439 * This function will also prepare and send the segment when needed.
3441 * Return FALSE if the stream is EOS.
3444 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
3445 QtDemuxStream * stream, guint64 * offset, guint * size, guint64 * dts,
3446 guint64 * pts, guint64 * duration, gboolean * keyframe)
3448 QtDemuxSample *sample;
3449 guint64 time_position;
3452 g_return_val_if_fail (stream != NULL, FALSE);
3454 time_position = stream->time_position;
3455 if (G_UNLIKELY (time_position == -1))
3458 seg_idx = stream->segment_index;
3459 if (G_UNLIKELY (seg_idx == -1)) {
3460 /* find segment corresponding to time_position if we are looking
3462 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
3464 /* nothing found, we're really eos */
3469 /* different segment, activate it, sample_index will be set. */
3470 if (G_UNLIKELY (stream->segment_index != seg_idx))
3471 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
3473 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
3474 stream->sample_index, stream->n_samples);
3476 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
3479 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
3480 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
3481 stream->sample_index);
3485 /* now get the info for the sample we're at */
3486 sample = &stream->samples[stream->sample_index];
3488 *dts = QTSAMPLE_DTS (stream, sample);
3489 *pts = QTSAMPLE_PTS (stream, sample);
3490 *offset = sample->offset;
3491 *size = sample->size;
3492 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
3493 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
3500 stream->time_position = -1;
3505 /* move to the next sample in @stream.
3507 * Moves to the next segment when needed.
3510 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
3512 QtDemuxSample *sample;
3513 QtDemuxSegment *segment;
3515 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
3516 /* Mark the stream as EOS */
3517 GST_DEBUG_OBJECT (qtdemux,
3518 "reached max allowed sample %u, mark EOS", stream->to_sample);
3519 stream->time_position = -1;
3523 /* move to next sample */
3524 stream->sample_index++;
3525 stream->offset_in_sample = 0;
3527 /* get current segment */
3528 segment = &stream->segments[stream->segment_index];
3530 /* reached the last sample, we need the next segment */
3531 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
3534 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
3535 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
3536 stream->sample_index);
3540 /* get next sample */
3541 sample = &stream->samples[stream->sample_index];
3543 /* see if we are past the segment */
3544 if (G_UNLIKELY (gst_util_uint64_scale (sample->timestamp,
3545 GST_SECOND, stream->timescale) >= segment->media_stop))
3548 if (gst_util_uint64_scale (sample->timestamp, GST_SECOND,
3549 stream->timescale) >= segment->media_start) {
3550 /* inside the segment, update time_position, looks very familiar to
3551 * GStreamer segments, doesn't it? */
3552 stream->time_position =
3553 (gst_util_uint64_scale (sample->timestamp, GST_SECOND,
3554 stream->timescale) - segment->media_start) + segment->time;
3556 /* not yet in segment, time does not yet increment. This means
3557 * that we are still prerolling keyframes to the decoder so it can
3558 * decode the first sample of the segment. */
3559 stream->time_position = segment->time;
3563 /* move to the next segment */
3566 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
3568 if (stream->segment_index == stream->n_segments - 1) {
3569 /* are we at the end of the last segment, we're EOS */
3570 stream->time_position = -1;
3572 /* else we're only at the end of the current segment */
3573 stream->time_position = segment->stop_time;
3575 /* make sure we select a new segment */
3576 stream->segment_index = -1;
3581 gst_qtdemux_sync_streams (GstQTDemux * demux)
3585 if (demux->n_streams <= 1)
3588 for (i = 0; i < demux->n_streams; i++) {
3589 QtDemuxStream *stream;
3590 GstClockTime end_time;
3592 stream = demux->streams[i];
3597 /* TODO advance time on subtitle streams here, if any some day */
3599 /* some clips/trailers may have unbalanced streams at the end,
3600 * so send EOS on shorter stream to prevent stalling others */
3602 /* do not mess with EOS if SEGMENT seeking */
3603 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
3606 if (demux->pullbased) {
3607 /* loop mode is sample time based */
3608 if (stream->time_position != -1)
3611 /* push mode is byte position based */
3612 if (stream->n_samples &&
3613 stream->samples[stream->n_samples - 1].offset >= demux->offset)
3617 if (stream->sent_eos)
3620 /* only act if some gap */
3621 end_time = stream->segments[stream->n_segments - 1].stop_time;
3622 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
3623 ", stream end: %" GST_TIME_FORMAT,
3624 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
3625 if (end_time + 2 * GST_SECOND < demux->segment.position) {
3626 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
3627 GST_PAD_NAME (stream->pad));
3628 stream->sent_eos = TRUE;
3629 gst_pad_push_event (stream->pad, gst_event_new_eos ());
3634 /* EOS and NOT_LINKED need to be combined. This means that we return:
3636 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
3637 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
3639 static GstFlowReturn
3640 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
3644 gboolean unexpected = FALSE, not_linked = TRUE;
3646 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
3648 /* store the value */
3649 stream->last_ret = ret;
3651 /* any other error that is not-linked or eos can be returned right away */
3652 if (G_LIKELY (ret != GST_FLOW_EOS && ret != GST_FLOW_NOT_LINKED))
3655 /* only return NOT_LINKED if all other pads returned NOT_LINKED */
3656 for (i = 0; i < demux->n_streams; i++) {
3657 QtDemuxStream *ostream = demux->streams[i];
3659 ret = ostream->last_ret;
3661 /* no unexpected or unlinked, return */
3662 if (G_LIKELY (ret != GST_FLOW_EOS && ret != GST_FLOW_NOT_LINKED))
3665 /* we check to see if we have at least 1 unexpected or all unlinked */
3666 unexpected |= (ret == GST_FLOW_EOS);
3667 not_linked &= (ret == GST_FLOW_NOT_LINKED);
3670 /* when we get here, we all have unlinked or unexpected */
3672 ret = GST_FLOW_NOT_LINKED;
3673 else if (unexpected)
3676 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
3680 /* the input buffer metadata must be writable. Returns NULL when the buffer is
3681 * completely cliped */
3683 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
3686 guint64 start, stop, cstart, cstop, diff;
3687 GstClockTime pts, dts, duration;
3689 gint num_rate, denom_rate;
3694 osize = size = gst_buffer_get_size (buf);
3697 /* depending on the type, setup the clip parameters */
3698 if (stream->subtype == FOURCC_soun) {
3699 frame_size = stream->bytes_per_frame;
3700 num_rate = GST_SECOND;
3701 denom_rate = (gint) stream->rate;
3703 } else if (stream->subtype == FOURCC_vide) {
3705 num_rate = stream->fps_n;
3706 denom_rate = stream->fps_d;
3711 /* we can only clip if we have a valid pts */
3712 pts = GST_BUFFER_PTS (buf);
3713 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
3716 dts = GST_BUFFER_DTS (buf);
3717 duration = GST_BUFFER_DURATION (buf);
3719 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
3721 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
3725 stop = start + duration;
3727 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
3728 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
3731 /* see if some clipping happened */
3732 diff = cstart - start;
3739 /* bring clipped time to samples and to bytes */
3740 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
3743 GST_DEBUG_OBJECT (qtdemux,
3744 "clipping start to %" GST_TIME_FORMAT " %"
3745 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
3751 diff = stop - cstop;
3756 /* bring clipped time to samples and then to bytes */
3757 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
3759 GST_DEBUG_OBJECT (qtdemux,
3760 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
3761 " bytes", GST_TIME_ARGS (cstop), diff);
3766 if (offset != 0 || size != osize)
3767 gst_buffer_resize (buf, offset, size);
3769 GST_BUFFER_DTS (buf) = dts;
3770 GST_BUFFER_PTS (buf) = pts;
3771 GST_BUFFER_DURATION (buf) = duration;
3775 /* dropped buffer */
3778 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
3783 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
3788 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
3789 gst_buffer_unref (buf);
3794 /* the input buffer metadata must be writable,
3795 * but time/duration etc not yet set and need not be preserved */
3797 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
3804 /* not many cases for now */
3805 if (G_UNLIKELY (stream->fourcc == FOURCC_mp4s)) {
3806 /* send a one time dvd clut event */
3807 if (stream->pending_event && stream->pad)
3808 gst_pad_push_event (stream->pad, stream->pending_event);
3809 stream->pending_event = NULL;
3810 /* no further processing needed */
3811 stream->need_process = FALSE;
3814 if (G_UNLIKELY (stream->subtype != FOURCC_text
3815 && stream->subtype != FOURCC_sbtl)) {
3819 gst_buffer_map (buf, &map, GST_MAP_READ);
3821 /* empty buffer is sent to terminate previous subtitle */
3822 if (map.size <= 2) {
3823 gst_buffer_unmap (buf, &map);
3824 gst_buffer_unref (buf);
3828 nsize = GST_READ_UINT16_BE (map.data);
3829 nsize = MIN (nsize, map.size - 2);
3831 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
3834 /* takes care of UTF-8 validation or UTF-16 recognition,
3835 * no other encoding expected */
3836 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
3837 gst_buffer_unmap (buf, &map);
3839 gst_buffer_unref (buf);
3840 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
3842 /* this should not really happen unless the subtitle is corrupted */
3843 gst_buffer_unref (buf);
3847 /* FIXME ? convert optional subsequent style info to markup */
3852 /* Sets a buffer's attributes properly and pushes it downstream.
3853 * Also checks for additional actions and custom processing that may
3854 * need to be done first.
3856 static GstFlowReturn
3857 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
3858 QtDemuxStream * stream, GstBuffer * buf,
3859 guint64 dts, guint64 pts, guint64 duration, gboolean keyframe,
3860 guint64 position, guint64 byte_position)
3862 GstFlowReturn ret = GST_FLOW_OK;
3864 if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) {
3868 gst_buffer_map (buf, &map, GST_MAP_READ);
3869 url = g_strndup ((gchar *) map.data, map.size);
3870 gst_buffer_unmap (buf, &map);
3871 if (url != NULL && strlen (url) != 0) {
3872 /* we have RTSP redirect now */
3873 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
3874 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
3875 gst_structure_new ("redirect",
3876 "new-location", G_TYPE_STRING, url, NULL)));
3877 qtdemux->posted_redirect = TRUE;
3879 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
3885 /* position reporting */
3886 if (qtdemux->segment.rate >= 0) {
3887 qtdemux->segment.position = position;
3888 gst_qtdemux_sync_streams (qtdemux);
3891 if (G_UNLIKELY (!stream->pad)) {
3892 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
3893 gst_buffer_unref (buf);
3897 /* send out pending buffers */
3898 while (stream->buffers) {
3899 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
3901 if (G_UNLIKELY (stream->discont)) {
3902 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
3903 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
3904 stream->discont = FALSE;
3907 gst_pad_push (stream->pad, buffer);
3909 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
3912 /* we're going to modify the metadata */
3913 buf = gst_buffer_make_writable (buf);
3915 if (G_UNLIKELY (stream->need_process))
3916 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
3922 GST_BUFFER_DTS (buf) = dts;
3923 GST_BUFFER_PTS (buf) = pts;
3924 GST_BUFFER_DURATION (buf) = duration;
3925 GST_BUFFER_OFFSET (buf) = -1;
3926 GST_BUFFER_OFFSET_END (buf) = -1;
3928 if (G_UNLIKELY (stream->padding)) {
3929 gst_buffer_resize (buf, stream->padding, -1);
3932 if (G_UNLIKELY (qtdemux->element_index)) {
3933 GstClockTime stream_time;
3936 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
3938 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
3939 GST_LOG_OBJECT (qtdemux,
3940 "adding association %" GST_TIME_FORMAT "-> %"
3941 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
3942 gst_index_add_association (qtdemux->element_index,
3944 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
3945 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
3946 GST_FORMAT_BYTES, byte_position, NULL);
3951 if (stream->need_clip)
3952 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
3954 if (G_UNLIKELY (buf == NULL))
3957 if (G_UNLIKELY (stream->discont)) {
3958 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
3959 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
3960 stream->discont = FALSE;
3964 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
3966 GST_LOG_OBJECT (qtdemux,
3967 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
3968 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
3969 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
3970 GST_PAD_NAME (stream->pad));
3972 ret = gst_pad_push (stream->pad, buf);
3974 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
3975 /* mark position in stream, we'll need this to know when to send GAP event */
3976 stream->segment.position = pts + duration;
3983 static GstFlowReturn
3984 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
3986 GstFlowReturn ret = GST_FLOW_OK;
3987 GstBuffer *buf = NULL;
3988 QtDemuxStream *stream;
3991 guint64 dts = GST_CLOCK_TIME_NONE;
3992 guint64 pts = GST_CLOCK_TIME_NONE;
3993 guint64 duration = 0;
3994 gboolean keyframe = FALSE;
3995 guint sample_size = 0;
4000 gst_qtdemux_push_pending_newsegment (qtdemux);
4002 /* Figure out the next stream sample to output, min_time is expressed in
4003 * global time and runs over the edit list segments. */
4004 min_time = G_MAXUINT64;
4006 for (i = 0; i < qtdemux->n_streams; i++) {
4009 stream = qtdemux->streams[i];
4010 position = stream->time_position;
4012 /* position of -1 is EOS */
4013 if (position != -1 && position < min_time) {
4014 min_time = position;
4019 if (G_UNLIKELY (index == -1)) {
4020 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
4024 /* check for segment end */
4025 if (G_UNLIKELY (qtdemux->segment.stop != -1
4026 && qtdemux->segment.stop < min_time)) {
4027 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
4031 /* gap events for subtitle streams */
4032 for (i = 0; i < qtdemux->n_streams; i++) {
4033 stream = qtdemux->streams[i];
4034 if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
4035 || stream->subtype == FOURCC_sbtl) {
4036 /* send one second gap events until the stream catches up */
4037 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
4038 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
4039 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
4040 stream->segment.position + GST_SECOND < min_time) {
4042 gst_event_new_gap (stream->segment.position, GST_SECOND);
4043 gst_pad_push_event (stream->pad, gap);
4044 stream->segment.position += GST_SECOND;
4049 stream = qtdemux->streams[index];
4051 /* fetch info for the current sample of this stream */
4052 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &offset,
4053 &sample_size, &dts, &pts, &duration, &keyframe)))
4056 GST_DEBUG_OBJECT (qtdemux,
4057 "pushing from stream %d, offset %" G_GUINT64_FORMAT
4058 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
4059 ", duration %" GST_TIME_FORMAT, index, offset, sample_size,
4060 GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
4062 /* hmm, empty sample, skip and move to next sample */
4063 if (G_UNLIKELY (sample_size <= 0))
4066 /* last pushed sample was out of boundary, goto next sample */
4067 if (G_UNLIKELY (stream->last_ret == GST_FLOW_EOS))
4070 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
4073 GST_DEBUG_OBJECT (qtdemux,
4074 "size %d larger than stream max_buffer_size %d, trimming",
4075 sample_size, stream->max_buffer_size);
4077 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
4080 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
4083 if (stream->use_allocator) {
4084 /* if we have a per-stream allocator, use it */
4085 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
4088 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
4090 if (G_UNLIKELY (ret != GST_FLOW_OK))
4093 if (size != sample_size) {
4094 pts += gst_util_uint64_scale_int (GST_SECOND,
4095 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
4096 dts += gst_util_uint64_scale_int (GST_SECOND,
4097 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
4098 duration = gst_util_uint64_scale_int (GST_SECOND,
4099 size / stream->bytes_per_frame, stream->timescale);
4102 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
4103 dts, pts, duration, keyframe, min_time, offset);
4105 if (size != sample_size) {
4106 QtDemuxSample *sample = &stream->samples[stream->sample_index];
4107 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
4109 GstClockTime time_position = gst_util_uint64_scale (sample->timestamp +
4110 stream->offset_in_sample / stream->bytes_per_frame, GST_SECOND,
4112 if (time_position >= segment->media_start) {
4113 /* inside the segment, update time_position, looks very familiar to
4114 * GStreamer segments, doesn't it? */
4115 stream->time_position = (time_position - segment->media_start) +
4118 /* not yet in segment, time does not yet increment. This means
4119 * that we are still prerolling keyframes to the decoder so it can
4120 * decode the first sample of the segment. */
4121 stream->time_position = segment->time;
4126 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
4127 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
4128 * we have no more data for the pad to push */
4129 if (ret == GST_FLOW_EOS)
4132 stream->offset_in_sample += size;
4133 if (stream->offset_in_sample >= sample_size) {
4134 gst_qtdemux_advance_sample (qtdemux, stream);
4139 gst_qtdemux_advance_sample (qtdemux, stream);
4147 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
4153 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
4154 /* EOS will be raised if all are EOS */
4161 gst_qtdemux_loop (GstPad * pad)
4163 GstQTDemux *qtdemux;
4167 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
4169 cur_offset = qtdemux->offset;
4170 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %d",
4171 cur_offset, qtdemux->state);
4173 switch (qtdemux->state) {
4174 case QTDEMUX_STATE_INITIAL:
4175 case QTDEMUX_STATE_HEADER:
4176 ret = gst_qtdemux_loop_state_header (qtdemux);
4178 case QTDEMUX_STATE_MOVIE:
4179 ret = gst_qtdemux_loop_state_movie (qtdemux);
4180 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
4181 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
4189 /* if something went wrong, pause */
4190 if (ret != GST_FLOW_OK)
4194 gst_object_unref (qtdemux);
4200 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
4201 (NULL), ("streaming stopped, invalid state"));
4202 gst_pad_pause_task (pad);
4203 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
4208 const gchar *reason = gst_flow_get_name (ret);
4210 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
4212 gst_pad_pause_task (pad);
4214 /* fatal errors need special actions */
4216 if (ret == GST_FLOW_EOS) {
4217 if (qtdemux->n_streams == 0) {
4218 /* we have no streams, post an error */
4219 gst_qtdemux_post_no_playable_stream_error (qtdemux);
4221 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
4224 if ((stop = qtdemux->segment.stop) == -1)
4225 stop = qtdemux->segment.duration;
4227 if (qtdemux->segment.rate >= 0) {
4228 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
4229 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
4230 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
4231 GST_FORMAT_TIME, stop));
4232 gst_qtdemux_push_event (qtdemux,
4233 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
4235 /* For Reverse Playback */
4236 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
4237 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
4238 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
4239 GST_FORMAT_TIME, qtdemux->segment.start));
4240 gst_qtdemux_push_event (qtdemux,
4241 gst_event_new_segment_done (GST_FORMAT_TIME,
4242 qtdemux->segment.start));
4245 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
4246 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
4248 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
4249 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
4250 (NULL), ("streaming stopped, reason %s", reason));
4251 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
4260 * Returns the size of the first entry at the current offset.
4261 * If -1, there are none (which means EOS or empty file).
4264 next_entry_size (GstQTDemux * demux)
4266 QtDemuxStream *stream;
4269 guint64 smalloffs = (guint64) - 1;
4270 QtDemuxSample *sample;
4272 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
4275 for (i = 0; i < demux->n_streams; i++) {
4276 stream = demux->streams[i];
4278 if (stream->sample_index == -1) {
4279 stream->sample_index = 0;
4280 stream->offset_in_sample = 0;
4283 if (stream->sample_index >= stream->n_samples) {
4284 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
4288 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
4289 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
4290 stream->sample_index);
4294 sample = &stream->samples[stream->sample_index];
4296 GST_LOG_OBJECT (demux,
4297 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
4298 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
4299 sample->offset, sample->size);
4301 if (((smalloffs == -1)
4302 || (sample->offset < smalloffs)) && (sample->size)) {
4304 smalloffs = sample->offset;
4308 GST_LOG_OBJECT (demux,
4309 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
4310 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
4315 stream = demux->streams[smallidx];
4316 sample = &stream->samples[stream->sample_index];
4318 if (sample->offset >= demux->offset) {
4319 demux->todrop = sample->offset - demux->offset;
4320 return sample->size + demux->todrop;
4323 GST_DEBUG_OBJECT (demux,
4324 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
4329 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
4331 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
4333 gst_element_post_message (GST_ELEMENT_CAST (demux),
4334 gst_message_new_element (GST_OBJECT_CAST (demux),
4335 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
4339 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
4344 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
4347 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
4348 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
4349 GST_SEEK_TYPE_NONE, -1);
4351 res = gst_pad_push_event (demux->sinkpad, event);
4356 /* check for seekable upstream, above and beyond a mere query */
4358 gst_qtdemux_check_seekability (GstQTDemux * demux)
4361 gboolean seekable = FALSE;
4362 gint64 start = -1, stop = -1;
4364 if (demux->upstream_size)
4367 query = gst_query_new_seeking (GST_FORMAT_BYTES);
4368 if (!gst_pad_peer_query (demux->sinkpad, query)) {
4369 GST_DEBUG_OBJECT (demux, "seeking query failed");
4373 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
4375 /* try harder to query upstream size if we didn't get it the first time */
4376 if (seekable && stop == -1) {
4377 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
4378 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
4381 /* if upstream doesn't know the size, it's likely that it's not seekable in
4382 * practice even if it technically may be seekable */
4383 if (seekable && (start != 0 || stop <= start)) {
4384 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
4389 gst_query_unref (query);
4391 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
4392 G_GUINT64_FORMAT ")", seekable, start, stop);
4393 demux->upstream_seekable = seekable;
4394 demux->upstream_size = seekable ? stop : -1;
4397 /* FIXME, unverified after edit list updates */
4398 static GstFlowReturn
4399 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
4402 GstFlowReturn ret = GST_FLOW_OK;
4403 GstClockTime timestamp;
4405 demux = GST_QTDEMUX (parent);
4407 timestamp = GST_BUFFER_TIMESTAMP (inbuf);
4409 if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (timestamp))) {
4410 demux->base_timestamp = timestamp;
4411 GST_DEBUG_OBJECT (demux, "got base_timestamp %" GST_TIME_FORMAT,
4412 GST_TIME_ARGS (timestamp));
4415 gst_adapter_push (demux->adapter, inbuf);
4417 /* we never really mean to buffer that much */
4418 if (demux->neededbytes == -1) {
4422 GST_DEBUG_OBJECT (demux,
4423 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
4424 demux->neededbytes, gst_adapter_available (demux->adapter));
4426 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
4427 (ret == GST_FLOW_OK)) {
4429 GST_DEBUG_OBJECT (demux,
4430 "state:%d , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT,
4431 demux->state, demux->neededbytes, demux->offset);
4433 switch (demux->state) {
4434 case QTDEMUX_STATE_INITIAL:{
4439 gst_qtdemux_check_seekability (demux);
4441 data = gst_adapter_map (demux->adapter, demux->neededbytes);
4443 /* get fourcc/length, set neededbytes */
4444 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
4446 gst_adapter_unmap (demux->adapter);
4448 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
4449 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
4451 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4452 (_("This file is invalid and cannot be played.")),
4453 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
4454 GST_FOURCC_ARGS (fourcc)));
4455 ret = GST_FLOW_ERROR;
4458 if (fourcc == FOURCC_mdat) {
4459 if (demux->n_streams > 0) {
4460 /* we have the headers, start playback */
4461 demux->state = QTDEMUX_STATE_MOVIE;
4462 demux->neededbytes = next_entry_size (demux);
4463 demux->mdatleft = size;
4465 /* no headers yet, try to get them */
4468 guint64 old, target;
4471 old = demux->offset;
4472 target = old + size;
4474 /* try to jump over the atom with a seek */
4475 /* only bother if it seems worth doing so,
4476 * and avoids possible upstream/server problems */
4477 if (demux->upstream_seekable &&
4478 demux->upstream_size > 4 * (1 << 20)) {
4479 res = qtdemux_seek_offset (demux, target);
4481 GST_DEBUG_OBJECT (demux, "skipping seek");
4486 GST_DEBUG_OBJECT (demux, "seek success");
4487 /* remember the offset fo the first mdat so we can seek back to it
4488 * after we have the headers */
4489 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
4490 demux->first_mdat = old;
4491 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
4494 /* seek worked, continue reading */
4495 demux->offset = target;
4496 demux->neededbytes = 16;
4497 demux->state = QTDEMUX_STATE_INITIAL;
4499 /* seek failed, need to buffer */
4500 demux->offset = old;
4501 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
4502 /* there may be multiple mdat (or alike) buffers */
4504 if (demux->mdatbuffer)
4505 bs = gst_buffer_get_size (demux->mdatbuffer);
4508 if (size + bs > 10 * (1 << 20))
4510 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
4511 demux->neededbytes = size;
4512 if (!demux->mdatbuffer)
4513 demux->mdatoffset = demux->offset;
4516 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
4517 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4518 (_("This file is invalid and cannot be played.")),
4519 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
4520 GST_FOURCC_ARGS (fourcc), size));
4521 ret = GST_FLOW_ERROR;
4524 /* this means we already started buffering and still no moov header,
4525 * let's continue buffering everything till we get moov */
4526 if (demux->mdatbuffer && (fourcc != FOURCC_moov))
4528 demux->neededbytes = size;
4529 demux->state = QTDEMUX_STATE_HEADER;
4533 case QTDEMUX_STATE_HEADER:{
4537 GST_DEBUG_OBJECT (demux, "In header");
4539 data = gst_adapter_map (demux->adapter, demux->neededbytes);
4541 /* parse the header */
4542 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
4544 if (fourcc == FOURCC_moov) {
4545 /* in usual fragmented setup we could try to scan for more
4546 * and end up at the the moov (after mdat) again */
4547 if (demux->got_moov && demux->n_streams > 0) {
4548 GST_DEBUG_OBJECT (demux,
4549 "Skipping moov atom as we have one already");
4551 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
4553 if (demux->got_moov && demux->fragmented) {
4554 GST_DEBUG_OBJECT (demux,
4555 "Got a second moov, clean up data from old one");
4558 /* prepare newsegment to send when streaming actually starts */
4559 if (!demux->pending_newsegment)
4560 demux->pending_newsegment =
4561 gst_event_new_segment (&demux->segment);
4563 qtdemux_parse_moov (demux, data, demux->neededbytes);
4564 qtdemux_node_dump (demux, demux->moov_node);
4565 qtdemux_parse_tree (demux);
4566 qtdemux_prepare_streams (demux);
4567 if (!demux->got_moov)
4568 qtdemux_expose_streams (demux);
4572 for (n = 0; n < demux->n_streams; n++) {
4573 QtDemuxStream *stream = demux->streams[n];
4575 gst_qtdemux_configure_stream (demux, stream);
4579 demux->got_moov = TRUE;
4581 g_node_destroy (demux->moov_node);
4582 demux->moov_node = NULL;
4583 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
4585 } else if (fourcc == FOURCC_moof) {
4586 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
4587 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
4588 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
4589 demux->offset, NULL)) {
4590 gst_adapter_unmap (demux->adapter);
4591 ret = GST_FLOW_ERROR;
4594 if (demux->mss_mode) {
4595 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
4596 if (!demux->exposed) {
4597 if (!demux->pending_newsegment) {
4599 gst_segment_init (&segment, GST_FORMAT_TIME);
4600 demux->pending_newsegment = gst_event_new_segment (&segment);
4602 qtdemux_expose_streams (demux);
4606 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
4608 } else if (fourcc == FOURCC_ftyp) {
4609 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
4610 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
4611 } else if (fourcc == FOURCC_uuid) {
4612 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
4613 qtdemux_parse_uuid (demux, data, demux->neededbytes);
4615 GST_WARNING_OBJECT (demux,
4616 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
4617 GST_FOURCC_ARGS (fourcc));
4618 /* Let's jump that one and go back to initial state */
4620 gst_adapter_unmap (demux->adapter);
4623 if (demux->mdatbuffer && demux->n_streams) {
4624 /* the mdat was before the header */
4625 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
4626 demux->n_streams, demux->mdatbuffer);
4627 /* restore our adapter/offset view of things with upstream;
4628 * put preceding buffered data ahead of current moov data.
4629 * This should also handle evil mdat, moov, mdat cases and alike */
4630 gst_adapter_clear (demux->adapter);
4631 gst_adapter_push (demux->adapter, demux->mdatbuffer);
4632 demux->mdatbuffer = NULL;
4633 demux->offset = demux->mdatoffset;
4634 demux->neededbytes = next_entry_size (demux);
4635 demux->state = QTDEMUX_STATE_MOVIE;
4636 demux->mdatleft = gst_adapter_available (demux->adapter);
4638 GST_DEBUG_OBJECT (demux, "Carrying on normally");
4639 gst_adapter_flush (demux->adapter, demux->neededbytes);
4641 if (demux->got_moov && demux->first_mdat != -1) {
4644 /* we need to seek back */
4645 res = qtdemux_seek_offset (demux, demux->first_mdat);
4647 demux->offset = demux->first_mdat;
4649 GST_DEBUG_OBJECT (demux, "Seek back failed");
4652 demux->offset += demux->neededbytes;
4654 demux->neededbytes = 16;
4655 demux->state = QTDEMUX_STATE_INITIAL;
4660 case QTDEMUX_STATE_BUFFER_MDAT:{
4664 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
4666 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
4667 gst_buffer_extract (buf, 0, fourcc, 4);
4668 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
4669 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
4670 if (demux->mdatbuffer)
4671 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
4673 demux->mdatbuffer = buf;
4674 demux->offset += demux->neededbytes;
4675 demux->neededbytes = 16;
4676 demux->state = QTDEMUX_STATE_INITIAL;
4677 gst_qtdemux_post_progress (demux, 1, 1);
4681 case QTDEMUX_STATE_MOVIE:{
4683 QtDemuxStream *stream = NULL;
4684 QtDemuxSample *sample;
4686 guint64 dts, pts, duration;
4689 GST_DEBUG_OBJECT (demux,
4690 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
4692 if (demux->fragmented) {
4693 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
4695 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
4696 /* if needed data starts within this atom,
4697 * then it should not exceed this atom */
4698 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
4699 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4700 (_("This file is invalid and cannot be played.")),
4701 ("sample data crosses atom boundary"));
4702 ret = GST_FLOW_ERROR;
4705 demux->mdatleft -= demux->neededbytes;
4707 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
4708 /* so we are dropping more than left in this atom */
4709 demux->todrop -= demux->mdatleft;
4710 demux->neededbytes -= demux->mdatleft;
4711 demux->mdatleft = 0;
4712 /* need to resume atom parsing so we do not miss any other pieces */
4713 demux->state = QTDEMUX_STATE_INITIAL;
4714 demux->neededbytes = 16;
4719 if (demux->todrop) {
4720 GST_LOG_OBJECT (demux, "Dropping %d bytes", demux->todrop);
4721 gst_adapter_flush (demux->adapter, demux->todrop);
4722 demux->neededbytes -= demux->todrop;
4723 demux->offset += demux->todrop;
4727 /* initial newsegment sent here after having added pads,
4728 * possible others in sink_event */
4729 if (G_UNLIKELY (demux->pending_newsegment)) {
4730 gst_qtdemux_push_pending_newsegment (demux);
4731 /* clear to send tags on all streams */
4732 for (i = 0; i < demux->n_streams; i++) {
4733 gst_qtdemux_push_tags (demux, demux->streams[i]);
4737 /* Figure out which stream this is packet belongs to */
4738 for (i = 0; i < demux->n_streams; i++) {
4739 stream = demux->streams[i];
4740 if (stream->sample_index >= stream->n_samples)
4742 GST_LOG_OBJECT (demux,
4743 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
4744 " / size:%d)", i, stream->sample_index,
4745 stream->samples[stream->sample_index].offset,
4746 stream->samples[stream->sample_index].size);
4748 if (stream->samples[stream->sample_index].offset == demux->offset)
4752 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
4753 goto unknown_stream;
4755 /* Put data in a buffer, set timestamps, caps, ... */
4756 outbuf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
4757 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
4758 GST_FOURCC_ARGS (stream->fourcc));
4760 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
4762 sample = &stream->samples[stream->sample_index];
4764 dts = QTSAMPLE_DTS (stream, sample);
4765 pts = QTSAMPLE_PTS (stream, sample);
4766 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
4767 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
4769 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
4770 dts, pts, duration, keyframe, dts, demux->offset);
4773 ret = gst_qtdemux_combine_flows (demux, stream, ret);
4775 stream->sample_index++;
4776 stream->offset_in_sample = 0;
4778 /* update current offset and figure out size of next buffer */
4779 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
4780 demux->offset, demux->neededbytes);
4781 demux->offset += demux->neededbytes;
4782 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
4785 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
4786 if (demux->fragmented) {
4787 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
4788 /* there may be more to follow, only finish this atom */
4789 demux->todrop = demux->mdatleft;
4790 demux->neededbytes = demux->todrop;
4802 /* when buffering movie data, at least show user something is happening */
4803 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
4804 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
4805 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
4806 demux->neededbytes);
4815 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
4816 ret = GST_FLOW_ERROR;
4821 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
4827 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
4828 (NULL), ("qtdemuxer invalid state %d", demux->state));
4829 ret = GST_FLOW_ERROR;
4834 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
4835 (NULL), ("no 'moov' atom within the first 10 MB"));
4836 ret = GST_FLOW_ERROR;
4842 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
4847 query = gst_query_new_scheduling ();
4849 if (!gst_pad_peer_query (sinkpad, query)) {
4850 gst_query_unref (query);
4854 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
4855 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
4856 gst_query_unref (query);
4861 GST_DEBUG_OBJECT (sinkpad, "activating pull");
4862 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
4866 GST_DEBUG_OBJECT (sinkpad, "activating push");
4867 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
4872 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
4873 GstPadMode mode, gboolean active)
4876 GstQTDemux *demux = GST_QTDEMUX (parent);
4879 case GST_PAD_MODE_PUSH:
4880 demux->pullbased = FALSE;
4883 case GST_PAD_MODE_PULL:
4885 demux->pullbased = TRUE;
4886 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
4889 res = gst_pad_stop_task (sinkpad);
4901 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
4903 return g_malloc (items * size);
4907 qtdemux_zfree (void *opaque, void *addr)
4913 qtdemux_inflate (void *z_buffer, guint z_length, guint length)
4919 z = g_new0 (z_stream, 1);
4920 z->zalloc = qtdemux_zalloc;
4921 z->zfree = qtdemux_zfree;
4924 z->next_in = z_buffer;
4925 z->avail_in = z_length;
4927 buffer = (guint8 *) g_malloc (length);
4928 ret = inflateInit (z);
4929 while (z->avail_in > 0) {
4930 if (z->avail_out == 0) {
4932 buffer = (guint8 *) g_realloc (buffer, length);
4933 z->next_out = buffer + z->total_out;
4934 z->avail_out = 1024;
4936 ret = inflate (z, Z_SYNC_FLUSH);
4940 if (ret != Z_STREAM_END) {
4941 g_warning ("inflate() returned %d", ret);
4947 #endif /* HAVE_ZLIB */
4950 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
4954 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
4956 /* counts as header data */
4957 qtdemux->header_size += length;
4959 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
4960 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
4962 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
4968 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
4969 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
4970 if (dcom == NULL || cmvd == NULL)
4971 goto invalid_compression;
4973 method = QT_FOURCC ((guint8 *) dcom->data + 8);
4976 case GST_MAKE_FOURCC ('z', 'l', 'i', 'b'):{
4977 guint uncompressed_length;
4978 guint compressed_length;
4981 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
4982 compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12;
4983 GST_LOG ("length = %u", uncompressed_length);
4986 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
4987 compressed_length, uncompressed_length);
4989 qtdemux->moov_node_compressed = qtdemux->moov_node;
4990 qtdemux->moov_node = g_node_new (buf);
4992 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
4993 uncompressed_length);
4996 #endif /* HAVE_ZLIB */
4998 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
4999 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
5006 invalid_compression:
5008 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
5014 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
5017 while (G_UNLIKELY (buf < end)) {
5021 if (G_UNLIKELY (buf + 4 > end)) {
5022 GST_LOG_OBJECT (qtdemux, "buffer overrun");
5025 len = QT_UINT32 (buf);
5026 if (G_UNLIKELY (len == 0)) {
5027 GST_LOG_OBJECT (qtdemux, "empty container");
5030 if (G_UNLIKELY (len < 8)) {
5031 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
5034 if (G_UNLIKELY (len > (end - buf))) {
5035 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
5036 (gint) (end - buf));
5040 child = g_node_new ((guint8 *) buf);
5041 g_node_append (node, child);
5042 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
5043 qtdemux_parse_node (qtdemux, child, buf, len);
5051 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
5054 int len = QT_UINT32 (xdxt->data);
5055 guint8 *buf = xdxt->data;
5056 guint8 *end = buf + len;
5059 /* skip size and type */
5067 size = QT_UINT32 (buf);
5068 type = QT_FOURCC (buf + 4);
5070 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
5072 if (buf + size > end || size <= 0)
5078 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
5079 GST_FOURCC_ARGS (type));
5083 buffer = gst_buffer_new_and_alloc (size);
5084 _gst_buffer_copy_into_mem (buffer, 0, buf, size);
5085 stream->buffers = g_slist_append (stream->buffers, buffer);
5086 GST_LOG_OBJECT (qtdemux, "parsing theora header");
5089 buffer = gst_buffer_new_and_alloc (size);
5090 _gst_buffer_copy_into_mem (buffer, 0, buf, size);
5091 stream->buffers = g_slist_append (stream->buffers, buffer);
5092 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
5095 buffer = gst_buffer_new_and_alloc (size);
5096 _gst_buffer_copy_into_mem (buffer, 0, buf, size);
5097 stream->buffers = g_slist_append (stream->buffers, buffer);
5098 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
5101 GST_WARNING_OBJECT (qtdemux,
5102 "unknown theora cookie %" GST_FOURCC_FORMAT,
5103 GST_FOURCC_ARGS (type));
5112 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
5116 guint32 node_length = 0;
5117 const QtNodeType *type;
5120 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
5122 if (G_UNLIKELY (length < 8))
5123 goto not_enough_data;
5125 node_length = QT_UINT32 (buffer);
5126 fourcc = QT_FOURCC (buffer + 4);
5128 /* ignore empty nodes */
5129 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
5132 type = qtdemux_type_get (fourcc);
5134 end = buffer + length;
5136 GST_LOG_OBJECT (qtdemux,
5137 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
5138 GST_FOURCC_ARGS (fourcc), node_length, type->name);
5140 if (node_length > length)
5141 goto broken_atom_size;
5143 if (type->flags & QT_FLAG_CONTAINER) {
5144 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
5149 if (node_length < 20) {
5150 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
5153 GST_DEBUG_OBJECT (qtdemux,
5154 "parsing stsd (sample table, sample description) atom");
5155 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
5165 /* also read alac (or whatever) in stead of mp4a in the following,
5166 * since a similar layout is used in other cases as well */
5167 if (fourcc == FOURCC_mp4a)
5172 /* There are two things we might encounter here: a true mp4a atom, and
5173 an mp4a entry in an stsd atom. The latter is what we're interested
5174 in, and it looks like an atom, but isn't really one. The true mp4a
5175 atom is short, so we detect it based on length here. */
5176 if (length < min_size) {
5177 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
5178 GST_FOURCC_ARGS (fourcc));
5182 /* 'version' here is the sound sample description version. Types 0 and
5183 1 are documented in the QTFF reference, but type 2 is not: it's
5184 described in Apple header files instead (struct SoundDescriptionV2
5186 version = QT_UINT16 (buffer + 16);
5188 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
5189 GST_FOURCC_ARGS (fourcc), version);
5191 /* parse any esds descriptors */
5203 GST_WARNING_OBJECT (qtdemux,
5204 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
5205 GST_FOURCC_ARGS (fourcc), version);
5210 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
5227 /* codec_data is contained inside these atoms, which all have
5228 * the same format. */
5230 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
5231 GST_FOURCC_ARGS (fourcc));
5232 version = QT_UINT32 (buffer + 16);
5233 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
5234 if (1 || version == 0x00000000) {
5235 buf = buffer + 0x32;
5237 /* FIXME Quicktime uses PASCAL string while
5238 * the iso format uses C strings. Check the file
5239 * type before attempting to parse the string here. */
5240 tlen = QT_UINT8 (buf);
5241 GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
5243 GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
5244 /* the string has a reserved space of 32 bytes so skip
5245 * the remaining 31 */
5247 buf += 4; /* and 4 bytes reserved */
5249 GST_MEMDUMP_OBJECT (qtdemux, "mp4v", buf, end - buf);
5251 qtdemux_parse_container (qtdemux, node, buf, end);
5257 GST_MEMDUMP_OBJECT (qtdemux, "avc1", buffer, end - buffer);
5258 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
5263 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
5268 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
5269 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
5277 version = QT_UINT32 (buffer + 12);
5278 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
5285 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
5290 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
5295 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
5299 if (!strcmp (type->name, "unknown"))
5300 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
5304 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
5305 GST_FOURCC_ARGS (fourcc));
5311 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5312 (_("This file is corrupt and cannot be played.")),
5313 ("Not enough data for an atom header, got only %u bytes", length));
5318 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5319 (_("This file is corrupt and cannot be played.")),
5320 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
5321 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
5328 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
5332 guint32 child_fourcc;
5334 for (child = g_node_first_child (node); child;
5335 child = g_node_next_sibling (child)) {
5336 buffer = (guint8 *) child->data;
5338 child_fourcc = QT_FOURCC (buffer + 4);
5340 if (G_UNLIKELY (child_fourcc == fourcc)) {
5348 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
5349 GstByteReader * parser)
5353 guint32 child_fourcc, child_len;
5355 for (child = g_node_first_child (node); child;
5356 child = g_node_next_sibling (child)) {
5357 buffer = (guint8 *) child->data;
5359 child_len = QT_UINT32 (buffer);
5360 child_fourcc = QT_FOURCC (buffer + 4);
5362 if (G_UNLIKELY (child_fourcc == fourcc)) {
5363 if (G_UNLIKELY (child_len < (4 + 4)))
5365 /* FIXME: must verify if atom length < parent atom length */
5366 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
5374 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
5375 GstByteReader * parser)
5379 guint32 child_fourcc, child_len;
5381 for (child = g_node_next_sibling (node); child;
5382 child = g_node_next_sibling (child)) {
5383 buffer = (guint8 *) child->data;
5385 child_fourcc = QT_FOURCC (buffer + 4);
5387 if (child_fourcc == fourcc) {
5389 child_len = QT_UINT32 (buffer);
5390 if (G_UNLIKELY (child_len < (4 + 4)))
5392 /* FIXME: must verify if atom length < parent atom length */
5393 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
5402 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
5404 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
5408 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
5412 query = gst_query_new_allocation (stream->caps, FALSE);
5414 if (!gst_pad_peer_query (stream->pad, query)) {
5415 /* not a problem, just debug a little */
5416 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
5419 if (stream->allocator)
5420 gst_object_unref (stream->allocator);
5422 if (gst_query_get_n_allocation_params (query) > 0) {
5423 /* try the allocator */
5424 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
5426 stream->use_allocator = TRUE;
5428 stream->allocator = NULL;
5429 gst_allocation_params_init (&stream->params);
5430 stream->use_allocator = FALSE;
5432 gst_query_unref (query);
5436 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
5438 if (stream->subtype == FOURCC_vide) {
5439 /* fps is calculated base on the duration of the first frames since
5440 * qt does not have a fixed framerate. */
5441 if ((stream->n_samples == 1) && (stream->min_duration == 0)) {
5446 stream->fps_n = stream->timescale;
5447 if (stream->min_duration == 0)
5450 stream->fps_d = stream->min_duration;
5455 gint depth, palette_count;
5456 const guint32 *palette_data = NULL;
5458 stream->caps = gst_caps_make_writable (stream->caps);
5460 gst_caps_set_simple (stream->caps,
5461 "width", G_TYPE_INT, stream->width,
5462 "height", G_TYPE_INT, stream->height,
5463 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
5465 /* calculate pixel-aspect-ratio using display width and height */
5466 GST_DEBUG_OBJECT (qtdemux,
5467 "video size %dx%d, target display size %dx%d", stream->width,
5468 stream->height, stream->display_width, stream->display_height);
5470 if (stream->display_width > 0 && stream->display_height > 0 &&
5471 stream->width > 0 && stream->height > 0) {
5474 /* calculate the pixel aspect ratio using the display and pixel w/h */
5475 n = stream->display_width * stream->height;
5476 d = stream->display_height * stream->width;
5479 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
5480 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
5481 GST_TYPE_FRACTION, n, d, NULL);
5484 /* qt file might have pasp atom */
5485 if (stream->par_w > 0 && stream->par_h > 0) {
5486 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
5487 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
5488 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
5491 depth = stream->bits_per_sample;
5493 /* more than 32 bits means grayscale */
5494 gray = (depth > 32);
5495 /* low 32 bits specify the depth */
5498 /* different number of palette entries is determined by depth. */
5500 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
5501 palette_count = (1 << depth);
5503 switch (palette_count) {
5507 palette_data = ff_qt_default_palette_2;
5510 palette_data = ff_qt_default_palette_4;
5514 palette_data = ff_qt_grayscale_palette_16;
5516 palette_data = ff_qt_default_palette_16;
5520 palette_data = ff_qt_grayscale_palette_256;
5522 palette_data = ff_qt_default_palette_256;
5525 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
5526 (_("The video in this file might not play correctly.")),
5527 ("unsupported palette depth %d", depth));
5533 /* make sure it's not writable. We leave MALLOCDATA to NULL so that we
5534 * don't free any of the buffer data. */
5535 palette = _gst_buffer_new_wrapped ((gpointer) palette_data,
5536 palette_count * 4, NULL);
5538 gst_caps_set_simple (stream->caps, "palette_data",
5539 GST_TYPE_BUFFER, palette, NULL);
5540 gst_buffer_unref (palette);
5541 } else if (palette_count != 0) {
5542 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
5543 (NULL), ("Unsupported palette depth %d. Ignoring stream.", depth));
5545 gst_object_unref (stream->pad);
5549 } else if (stream->subtype == FOURCC_soun) {
5551 gst_caps_set_simple (stream->caps,
5552 "rate", G_TYPE_INT, (int) stream->rate,
5553 "channels", G_TYPE_INT, stream->n_channels, NULL);
5554 if (stream->n_channels > 2) {
5555 /* FIXME: Need to parse the 'chan' atom to get channel layouts
5556 * correctly; this is just the minimum we can do - assume
5557 * we don't actually have any channel positions. */
5558 gst_caps_set_simple (stream->caps,
5559 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
5567 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
5568 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
5569 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
5570 gst_pad_set_active (stream->pad, TRUE);
5572 gst_pad_use_fixed_caps (stream->pad);
5574 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
5576 gst_pad_create_stream_id_printf (stream->pad,
5577 GST_ELEMENT_CAST (qtdemux), "%03u", stream->track_id);
5578 gst_pad_push_event (stream->pad, gst_event_new_stream_start (stream_id));
5580 gst_pad_set_caps (stream->pad, stream->caps);
5587 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
5588 QtDemuxStream * stream, GstTagList * list)
5590 /* consistent default for push based mode */
5591 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
5593 if (stream->subtype == FOURCC_vide) {
5594 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
5597 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
5600 gst_qtdemux_configure_stream (qtdemux, stream);
5601 qtdemux->n_video_streams++;
5602 } else if (stream->subtype == FOURCC_soun) {
5603 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
5606 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
5608 gst_qtdemux_configure_stream (qtdemux, stream);
5609 qtdemux->n_audio_streams++;
5610 } else if (stream->subtype == FOURCC_strm) {
5611 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
5612 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
5613 || stream->subtype == FOURCC_sbtl) {
5614 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
5617 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
5619 gst_qtdemux_configure_stream (qtdemux, stream);
5620 qtdemux->n_sub_streams++;
5621 } else if (stream->caps) {
5622 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
5625 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
5627 qtdemux->n_video_streams++;
5629 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5634 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
5635 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
5636 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
5638 if (stream->pending_tags)
5639 gst_tag_list_unref (stream->pending_tags);
5640 stream->pending_tags = list;
5641 /* global tags go on each pad anyway */
5642 stream->send_global_tags = TRUE;
5644 qtdemux_do_allocation (qtdemux, stream);
5650 /* find next atom with @fourcc starting at @offset */
5651 static GstFlowReturn
5652 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
5653 guint64 * length, guint32 fourcc)
5659 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
5660 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
5666 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
5667 if (G_UNLIKELY (ret != GST_FLOW_OK))
5669 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
5672 gst_buffer_unref (buf);
5675 gst_buffer_map (buf, &map, GST_MAP_READ);
5676 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
5677 gst_buffer_unmap (buf, &map);
5678 gst_buffer_unref (buf);
5680 if (G_UNLIKELY (*length == 0)) {
5681 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
5682 ret = GST_FLOW_ERROR;
5686 if (lfourcc == fourcc) {
5687 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
5691 GST_LOG_OBJECT (qtdemux,
5692 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
5693 GST_FOURCC_ARGS (fourcc), *offset);
5702 /* might simply have had last one */
5703 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
5708 /* should only do something in pull mode */
5709 /* call with OBJECT lock */
5710 static GstFlowReturn
5711 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
5713 guint64 length, offset;
5714 GstBuffer *buf = NULL;
5715 GstFlowReturn ret = GST_FLOW_OK;
5716 GstFlowReturn res = GST_FLOW_OK;
5719 offset = qtdemux->moof_offset;
5720 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
5723 GST_DEBUG_OBJECT (qtdemux, "no next moof");
5724 return GST_FLOW_EOS;
5727 /* best not do pull etc with lock held */
5728 GST_OBJECT_UNLOCK (qtdemux);
5730 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
5731 if (ret != GST_FLOW_OK)
5734 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
5735 if (G_UNLIKELY (ret != GST_FLOW_OK))
5737 gst_buffer_map (buf, &map, GST_MAP_READ);
5738 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
5739 gst_buffer_unmap (buf, &map);
5740 gst_buffer_unref (buf);
5745 gst_buffer_unmap (buf, &map);
5746 gst_buffer_unref (buf);
5750 /* look for next moof */
5751 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
5752 if (G_UNLIKELY (ret != GST_FLOW_OK))
5756 GST_OBJECT_LOCK (qtdemux);
5758 qtdemux->moof_offset = offset;
5764 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
5766 res = GST_FLOW_ERROR;
5771 /* maybe upstream temporarily flushing */
5772 if (ret != GST_FLOW_FLUSHING) {
5773 GST_DEBUG_OBJECT (qtdemux, "no next moof");
5776 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
5777 /* resume at current position next time */
5784 /* initialise bytereaders for stbl sub-atoms */
5786 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
5788 stream->stbl_index = -1; /* no samples have yet been parsed */
5789 stream->sample_index = -1;
5791 /* time-to-sample atom */
5792 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
5795 /* copy atom data into a new buffer for later use */
5796 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
5798 /* skip version + flags */
5799 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
5800 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
5802 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
5804 /* make sure there's enough data */
5805 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
5806 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
5807 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
5808 stream->n_sample_times);
5809 if (!stream->n_sample_times)
5813 /* sync sample atom */
5814 stream->stps_present = FALSE;
5815 if ((stream->stss_present =
5816 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
5817 &stream->stss) ? TRUE : FALSE) == TRUE) {
5818 /* copy atom data into a new buffer for later use */
5819 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
5821 /* skip version + flags */
5822 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
5823 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
5826 if (stream->n_sample_syncs) {
5827 /* make sure there's enough data */
5828 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
5832 /* partial sync sample atom */
5833 if ((stream->stps_present =
5834 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
5835 &stream->stps) ? TRUE : FALSE) == TRUE) {
5836 /* copy atom data into a new buffer for later use */
5837 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
5839 /* skip version + flags */
5840 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
5841 !gst_byte_reader_get_uint32_be (&stream->stps,
5842 &stream->n_sample_partial_syncs))
5845 /* if there are no entries, the stss table contains the real
5847 if (stream->n_sample_partial_syncs) {
5848 /* make sure there's enough data */
5849 if (!qt_atom_parser_has_chunks (&stream->stps,
5850 stream->n_sample_partial_syncs, 4))
5857 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
5860 /* copy atom data into a new buffer for later use */
5861 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
5863 /* skip version + flags */
5864 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
5865 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
5868 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
5871 if (!stream->n_samples)
5874 /* sample-to-chunk atom */
5875 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
5878 /* copy atom data into a new buffer for later use */
5879 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
5881 /* skip version + flags */
5882 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
5883 !gst_byte_reader_get_uint32_be (&stream->stsc,
5884 &stream->n_samples_per_chunk))
5887 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
5888 stream->n_samples_per_chunk);
5890 /* make sure there's enough data */
5891 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
5897 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
5898 stream->co_size = sizeof (guint32);
5899 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
5901 stream->co_size = sizeof (guint64);
5905 /* copy atom data into a new buffer for later use */
5906 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
5908 /* skip version + flags */
5909 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
5912 /* chunks_are_chunks == 0 means treat chunks as samples */
5913 stream->chunks_are_chunks = !stream->sample_size || stream->sampled;
5914 if (stream->chunks_are_chunks) {
5915 /* skip number of entries */
5916 if (!gst_byte_reader_skip (&stream->stco, 4))
5919 /* make sure there are enough data in the stsz atom */
5920 if (!stream->sample_size) {
5921 /* different sizes for each sample */
5922 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
5926 /* treat chunks as samples */
5927 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
5931 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
5932 stream->n_samples, (guint) sizeof (QtDemuxSample),
5933 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
5935 if (stream->n_samples >=
5936 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
5937 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
5938 "be larger than %uMB (broken file?)", stream->n_samples,
5939 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
5943 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
5944 if (!stream->samples) {
5945 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
5951 /* composition time-to-sample */
5952 if ((stream->ctts_present =
5953 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
5954 &stream->ctts) ? TRUE : FALSE) == TRUE) {
5955 /* copy atom data into a new buffer for later use */
5956 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
5958 /* skip version + flags */
5959 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
5960 || !gst_byte_reader_get_uint32_be (&stream->ctts,
5961 &stream->n_composition_times))
5964 /* make sure there's enough data */
5965 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
5974 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5975 (_("This file is corrupt and cannot be played.")), (NULL));
5980 gst_qtdemux_stbl_free (stream);
5981 if (!qtdemux->fragmented) {
5982 /* not quite good */
5983 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
5986 /* may pick up samples elsewhere */
5992 /* collect samples from the next sample to be parsed up to sample @n for @stream
5993 * by reading the info from @stbl
5995 * This code can be executed from both the streaming thread and the seeking
5996 * thread so it takes the object lock to protect itself
5999 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
6002 QtDemuxSample *samples, *first, *cur, *last;
6003 guint32 n_samples_per_chunk;
6006 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
6007 GST_FOURCC_FORMAT ", pad %s", GST_FOURCC_ARGS (stream->fourcc),
6008 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
6010 n_samples = stream->n_samples;
6013 goto out_of_samples;
6015 GST_OBJECT_LOCK (qtdemux);
6016 if (n <= stream->stbl_index)
6017 goto already_parsed;
6019 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
6021 if (!stream->stsz.data) {
6022 /* so we already parsed and passed all the moov samples;
6023 * onto fragmented ones */
6024 g_assert (qtdemux->fragmented);
6028 /* pointer to the sample table */
6029 samples = stream->samples;
6031 /* starts from -1, moves to the next sample index to parse */
6032 stream->stbl_index++;
6034 /* keep track of the first and last sample to fill */
6035 first = &samples[stream->stbl_index];
6038 if (stream->chunks_are_chunks) {
6039 /* set the sample sizes */
6040 if (stream->sample_size == 0) {
6041 /* different sizes for each sample */
6042 for (cur = first; cur <= last; cur++) {
6043 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
6044 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
6045 (guint) (cur - samples), cur->size);
6048 /* samples have the same size */
6049 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
6050 for (cur = first; cur <= last; cur++)
6051 cur->size = stream->sample_size;
6055 n_samples_per_chunk = stream->n_samples_per_chunk;
6058 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
6061 if (stream->stsc_chunk_index >= stream->last_chunk
6062 || stream->stsc_chunk_index < stream->first_chunk) {
6063 stream->first_chunk =
6064 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
6065 stream->samples_per_chunk =
6066 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
6067 gst_byte_reader_skip_unchecked (&stream->stsc, 4);
6069 /* chunk numbers are counted from 1 it seems */
6070 if (G_UNLIKELY (stream->first_chunk == 0))
6073 --stream->first_chunk;
6075 /* the last chunk of each entry is calculated by taking the first chunk
6076 * of the next entry; except if there is no next, where we fake it with
6078 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
6079 stream->last_chunk = G_MAXUINT32;
6081 stream->last_chunk =
6082 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
6083 if (G_UNLIKELY (stream->last_chunk == 0))
6086 --stream->last_chunk;
6089 GST_LOG_OBJECT (qtdemux,
6090 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
6091 stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
6093 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
6096 if (stream->last_chunk != G_MAXUINT32) {
6097 if (!qt_atom_parser_peek_sub (&stream->stco,
6098 stream->first_chunk * stream->co_size,
6099 (stream->last_chunk - stream->first_chunk) * stream->co_size,
6104 stream->co_chunk = stream->stco;
6105 if (!gst_byte_reader_skip (&stream->co_chunk,
6106 stream->first_chunk * stream->co_size))
6110 stream->stsc_chunk_index = stream->first_chunk;
6113 last_chunk = stream->last_chunk;
6115 if (stream->chunks_are_chunks) {
6116 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
6117 guint32 samples_per_chunk;
6118 guint64 chunk_offset;
6120 if (!stream->stsc_sample_index
6121 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
6122 &stream->chunk_offset))
6125 samples_per_chunk = stream->samples_per_chunk;
6126 chunk_offset = stream->chunk_offset;
6128 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
6129 GST_LOG_OBJECT (qtdemux, "Creating entry %d with offset %"
6130 G_GUINT64_FORMAT "and size %d",
6131 (guint) (cur - samples), stream->chunk_offset, cur->size);
6133 cur->offset = chunk_offset;
6134 chunk_offset += cur->size;
6137 if (G_UNLIKELY (cur > last)) {
6139 stream->stsc_sample_index = k + 1;
6140 stream->chunk_offset = chunk_offset;
6141 stream->stsc_chunk_index = j;
6145 stream->stsc_sample_index = 0;
6147 stream->stsc_chunk_index = j;
6149 cur = &samples[stream->stsc_chunk_index];
6151 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
6154 stream->stsc_chunk_index = j;
6159 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
6162 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
6163 "%" G_GUINT64_FORMAT, j, cur->offset);
6165 if (stream->samples_per_frame * stream->bytes_per_frame) {
6167 (stream->samples_per_chunk * stream->n_channels) /
6168 stream->samples_per_frame * stream->bytes_per_frame;
6170 cur->size = stream->samples_per_chunk;
6173 GST_DEBUG_OBJECT (qtdemux,
6174 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
6175 j, GST_TIME_ARGS (gst_util_uint64_scale (stream->stco_sample_index,
6176 GST_SECOND, stream->timescale)), cur->size);
6178 cur->timestamp = stream->stco_sample_index;
6179 cur->duration = stream->samples_per_chunk;
6180 cur->keyframe = TRUE;
6183 stream->stco_sample_index += stream->samples_per_chunk;
6185 stream->stsc_chunk_index = j;
6187 stream->stsc_index++;
6190 if (!stream->chunks_are_chunks)
6194 guint32 n_sample_times;
6196 n_sample_times = stream->n_sample_times;
6199 for (i = stream->stts_index; i < n_sample_times; i++) {
6200 guint32 stts_samples;
6201 gint32 stts_duration;
6204 if (stream->stts_sample_index >= stream->stts_samples
6205 || !stream->stts_sample_index) {
6207 stream->stts_samples =
6208 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
6209 stream->stts_duration =
6210 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
6212 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
6213 i, stream->stts_samples, stream->stts_duration);
6215 stream->stts_sample_index = 0;
6218 stts_samples = stream->stts_samples;
6219 stts_duration = stream->stts_duration;
6220 stts_time = stream->stts_time;
6222 for (j = stream->stts_sample_index; j < stts_samples; j++) {
6223 GST_DEBUG_OBJECT (qtdemux,
6224 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
6225 (guint) (cur - samples), j,
6226 GST_TIME_ARGS (gst_util_uint64_scale (stts_time, GST_SECOND,
6227 stream->timescale)));
6229 cur->timestamp = stts_time;
6230 cur->duration = stts_duration;
6232 /* avoid 32-bit wrap-around,
6233 * but still mind possible 'negative' duration */
6234 stts_time += (gint64) stts_duration;
6237 if (G_UNLIKELY (cur > last)) {
6239 stream->stts_time = stts_time;
6240 stream->stts_sample_index = j + 1;
6244 stream->stts_sample_index = 0;
6245 stream->stts_time = stts_time;
6246 stream->stts_index++;
6248 /* fill up empty timestamps with the last timestamp, this can happen when
6249 * the last samples do not decode and so we don't have timestamps for them.
6250 * We however look at the last timestamp to estimate the track length so we
6251 * need something in here. */
6252 for (; cur < last; cur++) {
6253 GST_DEBUG_OBJECT (qtdemux,
6254 "fill sample %d: timestamp %" GST_TIME_FORMAT,
6255 (guint) (cur - samples),
6256 GST_TIME_ARGS (gst_util_uint64_scale (stream->stts_time, GST_SECOND,
6257 stream->timescale)));
6258 cur->timestamp = stream->stts_time;
6264 /* sample sync, can be NULL */
6265 if (stream->stss_present == TRUE) {
6266 guint32 n_sample_syncs;
6268 n_sample_syncs = stream->n_sample_syncs;
6270 if (!n_sample_syncs) {
6271 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
6272 stream->all_keyframe = TRUE;
6274 for (i = stream->stss_index; i < n_sample_syncs; i++) {
6275 /* note that the first sample is index 1, not 0 */
6278 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
6280 if (G_LIKELY (index > 0 && index <= n_samples)) {
6282 samples[index].keyframe = TRUE;
6283 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
6284 /* and exit if we have enough samples */
6285 if (G_UNLIKELY (index >= n)) {
6292 stream->stss_index = i;
6295 /* stps marks partial sync frames like open GOP I-Frames */
6296 if (stream->stps_present == TRUE) {
6297 guint32 n_sample_partial_syncs;
6299 n_sample_partial_syncs = stream->n_sample_partial_syncs;
6301 /* if there are no entries, the stss table contains the real
6303 if (n_sample_partial_syncs) {
6304 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
6305 /* note that the first sample is index 1, not 0 */
6308 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
6310 if (G_LIKELY (index > 0 && index <= n_samples)) {
6312 samples[index].keyframe = TRUE;
6313 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
6314 /* and exit if we have enough samples */
6315 if (G_UNLIKELY (index >= n)) {
6322 stream->stps_index = i;
6326 /* no stss, all samples are keyframes */
6327 stream->all_keyframe = TRUE;
6328 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
6333 /* composition time to sample */
6334 if (stream->ctts_present == TRUE) {
6335 guint32 n_composition_times;
6337 gint32 ctts_soffset;
6339 /* Fill in the pts_offsets */
6341 n_composition_times = stream->n_composition_times;
6343 for (i = stream->ctts_index; i < n_composition_times; i++) {
6344 if (stream->ctts_sample_index >= stream->ctts_count
6345 || !stream->ctts_sample_index) {
6346 stream->ctts_count =
6347 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
6348 stream->ctts_soffset =
6349 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
6350 stream->ctts_sample_index = 0;
6353 ctts_count = stream->ctts_count;
6354 ctts_soffset = stream->ctts_soffset;
6356 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
6357 cur->pts_offset = ctts_soffset;
6360 if (G_UNLIKELY (cur > last)) {
6362 stream->ctts_sample_index = j + 1;
6366 stream->ctts_sample_index = 0;
6367 stream->ctts_index++;
6371 stream->stbl_index = n;
6372 /* if index has been completely parsed, free data that is no-longer needed */
6373 if (n + 1 == stream->n_samples) {
6374 gst_qtdemux_stbl_free (stream);
6375 GST_DEBUG_OBJECT (qtdemux,
6376 "parsed all available samples; checking for more");
6377 while (n + 1 == stream->n_samples)
6378 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
6381 GST_OBJECT_UNLOCK (qtdemux);
6388 GST_LOG_OBJECT (qtdemux,
6389 "Tried to parse up to sample %u but this sample has already been parsed",
6391 /* if fragmented, there may be more */
6392 if (qtdemux->fragmented && n == stream->stbl_index)
6394 GST_OBJECT_UNLOCK (qtdemux);
6400 GST_LOG_OBJECT (qtdemux,
6401 "Tried to parse up to sample %u but there are only %u samples", n + 1,
6403 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
6404 (_("This file is corrupt and cannot be played.")), (NULL));
6409 GST_OBJECT_UNLOCK (qtdemux);
6410 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
6411 (_("This file is corrupt and cannot be played.")), (NULL));
6416 /* collect all segment info for @stream.
6419 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
6424 /* parse and prepare segment info from the edit list */
6425 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
6426 stream->n_segments = 0;
6427 stream->segments = NULL;
6428 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
6432 guint64 time, stime;
6435 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
6436 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
6439 buffer = elst->data;
6441 n_segments = QT_UINT32 (buffer + 12);
6443 /* we might allocate a bit too much, at least allocate 1 segment */
6444 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
6446 /* segments always start from 0 */
6450 for (i = 0; i < n_segments; i++) {
6453 QtDemuxSegment *segment;
6456 media_time = QT_UINT32 (buffer + 20 + i * 12);
6458 /* -1 media time is an empty segment, just ignore it */
6459 if (media_time == G_MAXUINT32)
6462 duration = QT_UINT32 (buffer + 16 + i * 12);
6464 segment = &stream->segments[count++];
6466 /* time and duration expressed in global timescale */
6467 segment->time = stime;
6468 /* add non scaled values so we don't cause roundoff errors */
6470 stime = gst_util_uint64_scale (time, GST_SECOND, qtdemux->timescale);
6471 segment->stop_time = stime;
6472 segment->duration = stime - segment->time;
6473 /* media_time expressed in stream timescale */
6474 segment->media_start =
6475 gst_util_uint64_scale (media_time, GST_SECOND, stream->timescale);
6476 segment->media_stop = segment->media_start + segment->duration;
6477 rate_int = GST_READ_UINT32_BE (buffer + 24 + i * 12);
6479 if (rate_int <= 1) {
6480 /* 0 is not allowed, some programs write 1 instead of the floating point
6482 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
6486 segment->rate = rate_int / 65536.0;
6489 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
6490 ", duration %" GST_TIME_FORMAT ", media_time %" GST_TIME_FORMAT
6491 ", rate %g, (%d)", i, GST_TIME_ARGS (segment->time),
6492 GST_TIME_ARGS (segment->duration),
6493 GST_TIME_ARGS (segment->media_start), segment->rate, rate_int);
6495 GST_DEBUG_OBJECT (qtdemux, "found %d non-empty segments", count);
6496 stream->n_segments = count;
6500 /* push based does not handle segments, so act accordingly here,
6501 * and warn if applicable */
6502 if (!qtdemux->pullbased) {
6503 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
6504 /* remove and use default one below, we stream like it anyway */
6505 g_free (stream->segments);
6506 stream->segments = NULL;
6507 stream->n_segments = 0;
6510 /* no segments, create one to play the complete trak */
6511 if (stream->n_segments == 0) {
6512 GstClockTime stream_duration =
6513 gst_util_uint64_scale (stream->duration, GST_SECOND, stream->timescale);
6515 if (stream->segments == NULL)
6516 stream->segments = g_new (QtDemuxSegment, 1);
6518 /* represent unknown our way */
6519 if (stream_duration == 0)
6520 stream_duration = -1;
6522 stream->segments[0].time = 0;
6523 stream->segments[0].stop_time = stream_duration;
6524 stream->segments[0].duration = stream_duration;
6525 stream->segments[0].media_start = 0;
6526 stream->segments[0].media_stop = stream_duration;
6527 stream->segments[0].rate = 1.0;
6529 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
6530 GST_TIME_ARGS (stream_duration));
6531 stream->n_segments = 1;
6533 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
6539 * Parses the stsd atom of a svq3 trak looking for
6540 * the SMI and gama atoms.
6543 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
6544 guint8 ** gamma, GstBuffer ** seqh)
6546 guint8 *_gamma = NULL;
6547 GstBuffer *_seqh = NULL;
6548 guint8 *stsd_data = stsd->data;
6549 guint32 length = QT_UINT32 (stsd_data);
6553 GST_WARNING_OBJECT (qtdemux, "stsd too short");
6559 version = QT_UINT16 (stsd_data);
6564 while (length > 8) {
6565 guint32 fourcc, size;
6567 size = QT_UINT32 (stsd_data);
6568 fourcc = QT_FOURCC (stsd_data + 4);
6569 data = stsd_data + 8;
6576 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
6577 " for gama atom, expected 12", size);
6582 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
6584 if (_seqh != NULL) {
6585 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
6586 " found, ignoring");
6588 seqh_size = QT_UINT32 (data + 4);
6589 if (seqh_size > 0) {
6590 _seqh = gst_buffer_new_and_alloc (seqh_size);
6591 _gst_buffer_copy_into_mem (_seqh, 0, data + 8, seqh_size);
6598 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
6599 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
6603 if (size <= length) {
6609 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
6612 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
6613 G_GUINT16_FORMAT, version);
6624 gst_buffer_unref (_seqh);
6629 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
6636 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
6637 * atom that might contain a 'data' atom with the rtsp uri.
6638 * This case was reported in bug #597497, some info about
6639 * the hndl atom can be found in TN1195
6641 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
6642 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
6645 guint32 dref_num_entries = 0;
6646 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
6647 gst_byte_reader_skip (&dref, 4) &&
6648 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
6651 /* search dref entries for hndl atom */
6652 for (i = 0; i < dref_num_entries; i++) {
6653 guint32 size = 0, type;
6654 guint8 string_len = 0;
6655 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
6656 qt_atom_parser_get_fourcc (&dref, &type)) {
6657 if (type == FOURCC_hndl) {
6658 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
6660 /* skip data reference handle bytes and the
6661 * following pascal string and some extra 4
6662 * bytes I have no idea what are */
6663 if (!gst_byte_reader_skip (&dref, 4) ||
6664 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
6665 !gst_byte_reader_skip (&dref, string_len + 4)) {
6666 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
6670 /* iterate over the atoms to find the data atom */
6671 while (gst_byte_reader_get_remaining (&dref) >= 8) {
6675 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
6676 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
6677 if (atom_type == FOURCC_data) {
6678 const guint8 *uri_aux = NULL;
6680 /* found the data atom that might contain the rtsp uri */
6681 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
6682 "hndl atom, interpreting it as an URI");
6683 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
6685 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
6686 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
6688 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
6689 "didn't contain a rtsp address");
6691 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
6696 /* skipping to the next entry */
6697 if (!gst_byte_reader_skip (&dref, atom_size - 8))
6700 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
6707 /* skip to the next entry */
6708 if (!gst_byte_reader_skip (&dref, size - 8))
6711 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
6714 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
6721 less_than (gconstpointer a, gconstpointer b)
6723 const guint32 *av = a, *bv = b;
6728 #define AMR_NB_ALL_MODES 0x81ff
6729 #define AMR_WB_ALL_MODES 0x83ff
6731 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
6733 /* The 'damr' atom is of the form:
6735 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
6736 * 32 b 8 b 16 b 8 b 8 b
6738 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
6739 * represents the highest mode used in the stream (and thus the maximum
6740 * bitrate), with a couple of special cases as seen below.
6743 /* Map of frame type ID -> bitrate */
6744 static const guint nb_bitrates[] = {
6745 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
6747 static const guint wb_bitrates[] = {
6748 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
6754 gst_buffer_map (buf, &map, GST_MAP_READ);
6756 if (map.size != 0x11) {
6757 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
6761 if (QT_FOURCC (map.data + 4) != GST_MAKE_FOURCC ('d', 'a', 'm', 'r')) {
6762 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
6763 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
6767 mode_set = QT_UINT16 (map.data + 13);
6769 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
6770 max_mode = 7 + (wb ? 1 : 0);
6772 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
6773 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
6775 if (max_mode == -1) {
6776 GST_DEBUG ("No mode indication was found (mode set) = %x",
6781 gst_buffer_unmap (buf, &map);
6782 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
6785 gst_buffer_unmap (buf, &map);
6790 * With each track we associate a new QtDemuxStream that contains all the info
6792 * traks that do not decode to something (like strm traks) will not have a pad.
6795 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
6810 QtDemuxStream *stream = NULL;
6811 GstTagList *list = NULL;
6812 gchar *codec = NULL;
6813 const guint8 *stsd_data;
6814 guint16 lang_code; /* quicktime lang code or packed iso code */
6816 guint32 tkhd_flags = 0;
6817 guint8 tkhd_version = 0;
6819 guint value_size, len;
6822 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
6824 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
6825 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
6826 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
6829 if ((tkhd_flags & 1) == 0)
6830 goto track_disabled;
6832 /* pick between 64 or 32 bits */
6833 value_size = tkhd_version == 1 ? 8 : 4;
6834 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
6835 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
6838 if (!qtdemux->got_moov) {
6839 if (!qtdemux->got_moov && qtdemux_find_stream (qtdemux, track_id))
6840 goto existing_stream;
6841 stream = _create_stream ();
6842 stream->track_id = track_id;
6844 stream = qtdemux_find_stream (qtdemux, track_id);
6846 GST_WARNING_OBJECT (qtdemux, "Stream not found, going to ignore it");
6850 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
6851 tkhd_version, tkhd_flags, stream->track_id);
6853 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
6856 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
6857 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
6858 if (qtdemux->major_brand != FOURCC_mjp2 ||
6859 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
6863 len = QT_UINT32 ((guint8 *) mdhd->data);
6864 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
6865 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
6866 if (version == 0x01000000) {
6869 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
6870 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
6871 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
6875 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
6876 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
6877 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
6880 if (lang_code < 0x800) {
6881 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
6883 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
6884 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
6885 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
6886 stream->lang_id[3] = 0;
6889 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
6891 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
6893 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
6894 lang_code, stream->lang_id);
6896 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
6899 /* fragmented files may have bogus duration in moov */
6900 if (!qtdemux->fragmented &&
6901 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
6902 guint64 tdur1, tdur2;
6904 /* don't overflow */
6905 tdur1 = stream->timescale * (guint64) qtdemux->duration;
6906 tdur2 = qtdemux->timescale * (guint64) stream->duration;
6909 * some of those trailers, nowadays, have prologue images that are
6910 * themselves vide tracks as well. I haven't really found a way to
6911 * identify those yet, except for just looking at their duration. */
6912 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
6913 GST_WARNING_OBJECT (qtdemux,
6914 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
6915 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
6916 "found, assuming preview image or something; skipping track",
6917 stream->duration, stream->timescale, qtdemux->duration,
6918 qtdemux->timescale);
6924 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
6927 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
6928 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
6930 len = QT_UINT32 ((guint8 *) hdlr->data);
6932 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
6933 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
6934 GST_FOURCC_ARGS (stream->subtype));
6936 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
6939 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
6943 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
6945 stsd_data = (const guint8 *) stsd->data;
6947 /* stsd should at least have one entry */
6948 len = QT_UINT32 (stsd_data);
6952 /* and that entry should fit within stsd */
6953 len = QT_UINT32 (stsd_data + 16);
6954 if (len > QT_UINT32 (stsd_data) + 16)
6956 GST_LOG_OBJECT (qtdemux, "stsd len: %d", len);
6958 stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
6959 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
6960 GST_FOURCC_ARGS (stream->fourcc));
6962 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi) ||
6963 ((fourcc & 0xFFFFFF00) == GST_MAKE_FOURCC ('e', 'n', 'c', 0)))
6964 goto error_encrypted;
6966 if (stream->subtype == FOURCC_vide) {
6967 guint32 w = 0, h = 0;
6969 stream->sampled = TRUE;
6971 /* version 1 uses some 64-bit ints */
6972 if (!gst_byte_reader_skip (&tkhd, 56 + value_size)
6973 || !gst_byte_reader_get_uint32_be (&tkhd, &w)
6974 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
6977 stream->display_width = w >> 16;
6978 stream->display_height = h >> 16;
6984 stream->width = QT_UINT16 (stsd_data + offset + 32);
6985 stream->height = QT_UINT16 (stsd_data + offset + 34);
6986 stream->fps_n = 0; /* this is filled in later */
6987 stream->fps_d = 0; /* this is filled in later */
6988 stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
6989 stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
6991 GST_LOG_OBJECT (qtdemux, "frame count: %u",
6992 QT_UINT16 (stsd_data + offset + 48));
6995 qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
6997 list = gst_tag_list_new_empty ();
6998 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6999 GST_TAG_VIDEO_CODEC, codec, NULL);
7006 /* pick 'the' stsd child */
7007 mp4v = qtdemux_tree_get_child_by_type (stsd, fourcc);
7009 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
7010 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
7014 const guint8 *pasp_data = (const guint8 *) pasp->data;
7016 stream->par_w = QT_UINT32 (pasp_data + 8);
7017 stream->par_h = QT_UINT32 (pasp_data + 12);
7024 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
7029 gint len = QT_UINT32 (stsd_data) - 0x66;
7030 const guint8 *avc_data = stsd_data + 0x66;
7033 while (len >= 0x8) {
7036 if (QT_UINT32 (avc_data) <= len)
7037 size = QT_UINT32 (avc_data) - 0x8;
7042 /* No real data, so break out */
7045 switch (QT_FOURCC (avc_data + 0x4)) {
7048 /* parse, if found */
7051 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
7053 /* First 4 bytes are the length of the atom, the next 4 bytes
7054 * are the fourcc, the next 1 byte is the version, and the
7055 * subsequent bytes are sequence parameter set like data. */
7056 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
7057 avc_data + 8 + 1, size - 1);
7059 buf = gst_buffer_new_and_alloc (size);
7060 _gst_buffer_copy_into_mem (buf, 0, avc_data + 0x8, size);
7061 gst_caps_set_simple (stream->caps,
7062 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7063 gst_buffer_unref (buf);
7069 guint avg_bitrate, max_bitrate;
7071 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
7075 max_bitrate = QT_UINT32 (avc_data + 0xc);
7076 avg_bitrate = QT_UINT32 (avc_data + 0x10);
7078 if (!max_bitrate && !avg_bitrate)
7081 /* Some muxers seem to swap the average and maximum bitrates
7082 * (I'm looking at you, YouTube), so we swap for sanity. */
7083 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
7084 guint temp = avg_bitrate;
7086 avg_bitrate = max_bitrate;
7091 list = gst_tag_list_new_empty ();
7093 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
7094 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7095 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
7097 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
7098 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7099 GST_TAG_BITRATE, avg_bitrate, NULL);
7110 avc_data += size + 8;
7122 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
7123 GST_FOURCC_ARGS (fourcc));
7125 /* codec data might be in glbl extension atom */
7127 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
7133 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
7135 len = QT_UINT32 (data);
7138 buf = gst_buffer_new_and_alloc (len);
7139 _gst_buffer_copy_into_mem (buf, 0, data + 8, len);
7140 gst_caps_set_simple (stream->caps,
7141 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7142 gst_buffer_unref (buf);
7149 /* see annex I of the jpeg2000 spec */
7150 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
7152 const gchar *colorspace = NULL;
7154 guint32 ncomp_map = 0;
7155 gint32 *comp_map = NULL;
7156 guint32 nchan_def = 0;
7157 gint32 *chan_def = NULL;
7159 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
7160 /* some required atoms */
7161 mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
7164 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
7168 /* number of components; redundant with info in codestream, but useful
7170 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
7171 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
7173 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
7175 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
7178 GST_DEBUG_OBJECT (qtdemux, "found colr");
7179 /* extract colour space info */
7180 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
7181 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
7183 colorspace = "sRGB";
7186 colorspace = "GRAY";
7189 colorspace = "sYUV";
7197 /* colr is required, and only values 16, 17, and 18 are specified,
7198 so error if we have no colorspace */
7201 /* extract component mapping */
7202 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
7204 guint32 cmap_len = 0;
7206 cmap_len = QT_UINT32 (cmap->data);
7207 if (cmap_len >= 8) {
7208 /* normal box, subtract off header */
7210 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
7211 if (cmap_len % 4 == 0) {
7212 ncomp_map = (cmap_len / 4);
7213 comp_map = g_new0 (gint32, ncomp_map);
7214 for (i = 0; i < ncomp_map; i++) {
7217 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
7218 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
7219 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
7220 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
7225 /* extract channel definitions */
7226 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
7228 guint32 cdef_len = 0;
7230 cdef_len = QT_UINT32 (cdef->data);
7231 if (cdef_len >= 10) {
7232 /* normal box, subtract off header and len */
7234 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
7235 if (cdef_len % 6 == 0) {
7236 nchan_def = (cdef_len / 6);
7237 chan_def = g_new0 (gint32, nchan_def);
7238 for (i = 0; i < nchan_def; i++)
7240 for (i = 0; i < nchan_def; i++) {
7241 guint16 cn, typ, asoc;
7242 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
7243 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
7244 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
7245 if (cn < nchan_def) {
7248 chan_def[cn] = asoc;
7251 chan_def[cn] = 0; /* alpha */
7254 chan_def[cn] = -typ;
7262 gst_caps_set_simple (stream->caps,
7263 "num-components", G_TYPE_INT, ncomp, NULL);
7264 gst_caps_set_simple (stream->caps,
7265 "colorspace", G_TYPE_STRING, colorspace, NULL);
7268 GValue arr = { 0, };
7269 GValue elt = { 0, };
7271 g_value_init (&arr, GST_TYPE_ARRAY);
7272 g_value_init (&elt, G_TYPE_INT);
7273 for (i = 0; i < ncomp_map; i++) {
7274 g_value_set_int (&elt, comp_map[i]);
7275 gst_value_array_append_value (&arr, &elt);
7277 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
7278 "component-map", &arr);
7279 g_value_unset (&elt);
7280 g_value_unset (&arr);
7285 GValue arr = { 0, };
7286 GValue elt = { 0, };
7288 g_value_init (&arr, GST_TYPE_ARRAY);
7289 g_value_init (&elt, G_TYPE_INT);
7290 for (i = 0; i < nchan_def; i++) {
7291 g_value_set_int (&elt, chan_def[i]);
7292 gst_value_array_append_value (&arr, &elt);
7294 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
7295 "channel-definitions", &arr);
7296 g_value_unset (&elt);
7297 g_value_unset (&arr);
7301 /* some optional atoms */
7302 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
7303 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
7305 /* indicate possible fields in caps */
7307 data = (guint8 *) field->data + 8;
7309 gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
7310 (gint) * data, NULL);
7312 /* add codec_data if provided */
7317 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
7318 data = prefix->data;
7319 len = QT_UINT32 (data);
7322 buf = gst_buffer_new_and_alloc (len);
7323 _gst_buffer_copy_into_mem (buf, 0, data + 8, len);
7324 gst_caps_set_simple (stream->caps,
7325 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7326 gst_buffer_unref (buf);
7335 GstBuffer *seqh = NULL;
7336 guint8 *gamma_data = NULL;
7337 gint len = QT_UINT32 (stsd_data);
7339 qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
7341 gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
7342 QT_FP32 (gamma_data), NULL);
7345 /* sorry for the bad name, but we don't know what this is, other
7346 * than its own fourcc */
7347 gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
7351 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
7352 buf = gst_buffer_new_and_alloc (len);
7353 _gst_buffer_copy_into_mem (buf, 0, stsd_data, len);
7354 gst_caps_set_simple (stream->caps,
7355 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7356 gst_buffer_unref (buf);
7361 gst_caps_set_simple (stream->caps,
7362 "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
7369 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
7370 xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
7374 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
7378 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
7379 /* collect the headers and store them in a stream list so that we can
7380 * send them out first */
7381 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
7391 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
7392 ovc1 = qtdemux_tree_get_child_by_type (stsd, FOURCC_ovc1);
7395 ovc1_data = ovc1->data;
7396 ovc1_len = QT_UINT32 (ovc1_data);
7397 if (ovc1_len <= 198) {
7398 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
7401 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
7402 _gst_buffer_copy_into_mem (buf, 0, ovc1_data + 198, ovc1_len - 198);
7403 gst_caps_set_simple (stream->caps,
7404 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7405 gst_buffer_unref (buf);
7413 GST_INFO_OBJECT (qtdemux,
7414 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
7415 GST_FOURCC_ARGS (fourcc), stream->caps);
7417 } else if (stream->subtype == FOURCC_soun) {
7418 int version, samplesize;
7419 guint16 compression_id;
7420 gboolean amrwb = FALSE;
7423 /* sample description entry (16) + sound sample description v0 (20) */
7427 version = QT_UINT32 (stsd_data + offset);
7428 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
7429 samplesize = QT_UINT16 (stsd_data + offset + 10);
7430 compression_id = QT_UINT16 (stsd_data + offset + 12);
7431 stream->rate = QT_FP32 (stsd_data + offset + 16);
7433 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
7434 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
7435 QT_UINT32 (stsd_data + offset + 4));
7436 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
7437 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
7438 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
7439 GST_LOG_OBJECT (qtdemux, "packet size: %d",
7440 QT_UINT16 (stsd_data + offset + 14));
7441 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
7443 if (compression_id == 0xfffe)
7444 stream->sampled = TRUE;
7446 /* first assume uncompressed audio */
7447 stream->bytes_per_sample = samplesize / 8;
7448 stream->samples_per_frame = stream->n_channels;
7449 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
7450 stream->samples_per_packet = stream->samples_per_frame;
7451 stream->bytes_per_packet = stream->bytes_per_sample;
7455 /* Yes, these have to be hard-coded */
7458 stream->samples_per_packet = 6;
7459 stream->bytes_per_packet = 1;
7460 stream->bytes_per_frame = 1 * stream->n_channels;
7461 stream->bytes_per_sample = 1;
7462 stream->samples_per_frame = 6 * stream->n_channels;
7467 stream->samples_per_packet = 3;
7468 stream->bytes_per_packet = 1;
7469 stream->bytes_per_frame = 1 * stream->n_channels;
7470 stream->bytes_per_sample = 1;
7471 stream->samples_per_frame = 3 * stream->n_channels;
7476 stream->samples_per_packet = 64;
7477 stream->bytes_per_packet = 34;
7478 stream->bytes_per_frame = 34 * stream->n_channels;
7479 stream->bytes_per_sample = 2;
7480 stream->samples_per_frame = 64 * stream->n_channels;
7486 stream->samples_per_packet = 1;
7487 stream->bytes_per_packet = 1;
7488 stream->bytes_per_frame = 1 * stream->n_channels;
7489 stream->bytes_per_sample = 1;
7490 stream->samples_per_frame = 1 * stream->n_channels;
7495 stream->samples_per_packet = 160;
7496 stream->bytes_per_packet = 33;
7497 stream->bytes_per_frame = 33 * stream->n_channels;
7498 stream->bytes_per_sample = 2;
7499 stream->samples_per_frame = 160 * stream->n_channels;
7506 if (version == 0x00010000) {
7507 /* sample description entry (16) + sound sample description v1 (20+16) */
7518 /* only parse extra decoding config for non-pcm audio */
7519 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
7520 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
7521 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
7522 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
7524 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
7525 stream->samples_per_packet);
7526 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
7527 stream->bytes_per_packet);
7528 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
7529 stream->bytes_per_frame);
7530 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
7531 stream->bytes_per_sample);
7533 if (!stream->sampled && stream->bytes_per_packet) {
7534 stream->samples_per_frame = (stream->bytes_per_frame /
7535 stream->bytes_per_packet) * stream->samples_per_packet;
7536 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
7537 stream->samples_per_frame);
7542 } else if (version == 0x00020000) {
7549 /* sample description entry (16) + sound sample description v2 (56) */
7553 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
7554 stream->rate = qtfp.fp;
7555 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
7557 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
7558 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
7559 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
7560 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
7561 QT_UINT32 (stsd_data + offset + 20));
7562 GST_LOG_OBJECT (qtdemux, "format flags: %X",
7563 QT_UINT32 (stsd_data + offset + 24));
7564 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
7565 QT_UINT32 (stsd_data + offset + 28));
7566 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
7567 QT_UINT32 (stsd_data + offset + 32));
7569 GST_WARNING_OBJECT (qtdemux, "unknown version %08x", version);
7572 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc,
7573 stsd_data + 32, len - 16, &codec);
7581 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
7583 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
7585 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
7587 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
7590 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
7591 gst_caps_set_simple (stream->caps,
7592 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE", NULL);
7599 const guint8 *owma_data;
7600 const gchar *codec_name = NULL;
7604 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
7605 /* FIXME this should also be gst_riff_strf_auds,
7606 * but the latter one is actually missing bits-per-sample :( */
7611 gint32 nSamplesPerSec;
7612 gint32 nAvgBytesPerSec;
7614 gint16 wBitsPerSample;
7619 GST_DEBUG_OBJECT (qtdemux, "parse owma");
7620 owma = qtdemux_tree_get_child_by_type (stsd, FOURCC_owma);
7623 owma_data = owma->data;
7624 owma_len = QT_UINT32 (owma_data);
7625 if (owma_len <= 54) {
7626 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
7629 wfex = (WAVEFORMATEX *) (owma_data + 36);
7630 buf = gst_buffer_new_and_alloc (owma_len - 54);
7631 _gst_buffer_copy_into_mem (buf, 0, owma_data + 54, owma_len - 54);
7632 if (wfex->wFormatTag == 0x0161) {
7633 codec_name = "Windows Media Audio";
7635 } else if (wfex->wFormatTag == 0x0162) {
7636 codec_name = "Windows Media Audio 9 Pro";
7638 } else if (wfex->wFormatTag == 0x0163) {
7639 codec_name = "Windows Media Audio 9 Lossless";
7640 /* is that correct? gstffmpegcodecmap.c is missing it, but
7641 * fluendo codec seems to support it */
7645 gst_caps_set_simple (stream->caps,
7646 "codec_data", GST_TYPE_BUFFER, buf,
7647 "wmaversion", G_TYPE_INT, version,
7648 "block_align", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->nBlockAlign),
7649 "bitrate", G_TYPE_INT, GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec),
7650 "width", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
7651 "depth", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
7653 gst_buffer_unref (buf);
7657 codec = g_strdup (codec_name);
7669 list = gst_tag_list_new_empty ();
7670 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7671 GST_TAG_AUDIO_CODEC, codec, NULL);
7675 /* some bitrate info may have ended up in caps */
7676 s = gst_caps_get_structure (stream->caps, 0);
7677 gst_structure_get_int (s, "bitrate", &bitrate);
7679 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
7683 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
7687 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
7689 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
7691 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
7695 /* If the fourcc's bottom 16 bits gives 'sm', then the top
7696 16 bits is a byte-swapped wave-style codec identifier,
7697 and we can find a WAVE header internally to a 'wave' atom here.
7698 This can more clearly be thought of as 'ms' as the top 16 bits, and a
7699 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
7702 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
7703 if (len < offset + 20) {
7704 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
7706 guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
7707 const guint8 *data = stsd_data + offset + 16;
7709 GNode *waveheadernode;
7711 wavenode = g_node_new ((guint8 *) data);
7712 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
7713 const guint8 *waveheader;
7716 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
7717 if (waveheadernode) {
7718 waveheader = (const guint8 *) waveheadernode->data;
7719 headerlen = QT_UINT32 (waveheader);
7721 if (headerlen > 8) {
7722 gst_riff_strf_auds *header = NULL;
7723 GstBuffer *headerbuf;
7729 headerbuf = gst_buffer_new_and_alloc (headerlen);
7730 _gst_buffer_copy_into_mem (headerbuf, 0, waveheader, headerlen);
7732 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
7733 headerbuf, &header, &extra)) {
7734 gst_caps_unref (stream->caps);
7735 /* FIXME: Need to do something with the channel reorder map */
7736 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
7737 header, extra, NULL, NULL, NULL);
7740 gst_buffer_unref (extra);
7745 GST_DEBUG ("Didn't find waveheadernode for this codec");
7747 g_node_destroy (wavenode);
7750 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
7754 /* FIXME: what is in the chunk? */
7757 gint len = QT_UINT32 (stsd_data);
7759 /* seems to be always = 116 = 0x74 */
7765 gint len = QT_UINT32 (stsd_data);
7768 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
7770 _gst_buffer_copy_into_mem (buf, 0, stsd_data + 0x4C, len - 0x4C);
7771 gst_caps_set_simple (stream->caps,
7772 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7773 gst_buffer_unref (buf);
7775 gst_caps_set_simple (stream->caps,
7776 "samplesize", G_TYPE_INT, samplesize, NULL);
7781 GNode *alac, *wave = NULL;
7783 /* apparently, m4a has this atom appended directly in the stsd entry,
7784 * while mov has it in a wave atom */
7785 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
7787 /* alac now refers to stsd entry atom */
7788 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
7790 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
7792 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
7795 gint len = QT_UINT32 (alac->data);
7799 GST_DEBUG_OBJECT (qtdemux,
7800 "discarding alac atom with unexpected len %d", len);
7802 /* codec-data contains alac atom size and prefix,
7803 * ffmpeg likes it that way, not quite gst-ish though ...*/
7804 buf = gst_buffer_new_and_alloc (len);
7805 _gst_buffer_copy_into_mem (buf, 0, alac->data, len);
7806 gst_caps_set_simple (stream->caps,
7807 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7808 gst_buffer_unref (buf);
7811 gst_caps_set_simple (stream->caps,
7812 "samplesize", G_TYPE_INT, samplesize, NULL);
7820 gint len = QT_UINT32 (stsd_data);
7823 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
7826 _gst_buffer_copy_into_mem (buf, 0, stsd_data + 0x34, len - 0x34);
7828 /* If we have enough data, let's try to get the 'damr' atom. See
7829 * the 3GPP container spec (26.244) for more details. */
7830 if ((len - 0x34) > 8 &&
7831 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
7833 list = gst_tag_list_new_empty ();
7834 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7835 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
7838 gst_caps_set_simple (stream->caps,
7839 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7840 gst_buffer_unref (buf);
7848 GST_INFO_OBJECT (qtdemux,
7849 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
7850 GST_FOURCC_ARGS (fourcc), stream->caps);
7852 } else if (stream->subtype == FOURCC_strm) {
7853 if (fourcc == FOURCC_rtsp) {
7854 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
7856 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
7857 GST_FOURCC_ARGS (fourcc));
7858 goto unknown_stream;
7860 stream->sampled = TRUE;
7861 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
7862 || stream->subtype == FOURCC_sbtl) {
7864 stream->sampled = TRUE;
7869 qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
7871 list = gst_tag_list_new_empty ();
7872 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7873 GST_TAG_SUBTITLE_CODEC, codec, NULL);
7878 /* hunt for sort-of codec data */
7885 /* look for palette */
7886 /* target mp4s atom */
7887 len = QT_UINT32 (stsd_data + offset);
7888 data = stsd_data + offset;
7889 /* verify sufficient length,
7890 * and esds present with decConfigDescr of expected size and position */
7891 if ((len >= 106 + 8)
7892 && (QT_FOURCC (data + 8 + 8 + 4) == FOURCC_esds)
7893 && (QT_UINT16 (data + 8 + 40) == 0x0540)) {
7898 /* move to decConfigDescr data */
7899 data = data + 8 + 42;
7900 for (i = 0; i < 16; i++) {
7901 clut[i] = QT_UINT32 (data);
7905 s = gst_structure_new ("application/x-gst-dvd", "event",
7906 G_TYPE_STRING, "dvd-spu-clut-change",
7907 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
7908 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
7909 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
7910 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
7911 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
7912 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
7913 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
7914 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
7917 /* store event and trigger custom processing */
7918 stream->pending_event =
7919 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
7920 stream->need_process = TRUE;
7928 /* everything in 1 sample */
7929 stream->sampled = TRUE;
7932 qtdemux_generic_caps (qtdemux, stream, fourcc, stsd_data, &codec);
7934 if (stream->caps == NULL)
7935 goto unknown_stream;
7938 list = gst_tag_list_new_empty ();
7939 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7940 GST_TAG_SUBTITLE_CODEC, codec, NULL);
7946 /* promote to sampled format */
7947 if (stream->fourcc == FOURCC_samr) {
7948 /* force mono 8000 Hz for AMR */
7949 stream->sampled = TRUE;
7950 stream->n_channels = 1;
7951 stream->rate = 8000;
7952 } else if (stream->fourcc == FOURCC_sawb) {
7953 /* force mono 16000 Hz for AMR-WB */
7954 stream->sampled = TRUE;
7955 stream->n_channels = 1;
7956 stream->rate = 16000;
7957 } else if (stream->fourcc == FOURCC_mp4a) {
7958 stream->sampled = TRUE;
7961 /* collect sample information */
7962 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
7963 goto samples_failed;
7965 if (qtdemux->fragmented) {
7969 /* need all moov samples as basis; probably not many if any at all */
7970 /* prevent moof parsing taking of at this time */
7971 offset = qtdemux->moof_offset;
7972 qtdemux->moof_offset = 0;
7973 if (stream->n_samples &&
7974 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
7975 qtdemux->moof_offset = offset;
7976 goto samples_failed;
7978 qtdemux->moof_offset = 0;
7979 /* movie duration more reliable in this case (e.g. mehd) */
7980 if (qtdemux->segment.duration &&
7981 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
7982 stream->duration = gst_util_uint64_scale (qtdemux->segment.duration,
7983 stream->timescale, GST_SECOND);
7984 /* need defaults for fragments */
7985 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
7988 /* configure segments */
7989 if (!qtdemux_parse_segments (qtdemux, stream, trak))
7990 goto segments_failed;
7992 /* add some language tag, if useful */
7993 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
7994 strcmp (stream->lang_id, "und")) {
7995 const gchar *lang_code;
7998 list = gst_tag_list_new_empty ();
8000 /* convert ISO 639-2 code to ISO 639-1 */
8001 lang_code = gst_tag_get_language_code (stream->lang_id);
8002 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
8003 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
8006 /* now we are ready to add the stream */
8007 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
8008 goto too_many_streams;
8010 if (!qtdemux->got_moov) {
8011 stream->pending_tags = list;
8012 qtdemux->streams[qtdemux->n_streams] = stream;
8013 qtdemux->n_streams++;
8014 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
8022 GST_INFO_OBJECT (qtdemux, "skip disabled track");
8028 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8029 (_("This file is corrupt and cannot be played.")), (NULL));
8035 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
8042 /* we posted an error already */
8043 /* free stbl sub-atoms */
8044 gst_qtdemux_stbl_free (stream);
8050 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
8058 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
8059 GST_FOURCC_ARGS (stream->subtype));
8065 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
8066 (_("This file contains too many streams. Only playing first %d"),
8067 GST_QTDEMUX_MAX_STREAMS), (NULL));
8072 /* If we can estimate the overall bitrate, and don't have information about the
8073 * stream bitrate for exactly one stream, this guesses the stream bitrate as
8074 * the overall bitrate minus the sum of the bitrates of all other streams. This
8075 * should be useful for the common case where we have one audio and one video
8076 * stream and can estimate the bitrate of one, but not the other. */
8078 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
8080 QtDemuxStream *stream = NULL;
8081 gint64 size, duration, sys_bitrate, sum_bitrate = 0;
8085 if (qtdemux->fragmented)
8088 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
8090 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
8092 GST_DEBUG_OBJECT (qtdemux,
8093 "Size in bytes of the stream not known - bailing");
8097 /* Subtract the header size */
8098 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
8099 size, qtdemux->header_size);
8101 if (size < qtdemux->header_size)
8104 size = size - qtdemux->header_size;
8106 if (!gst_qtdemux_get_duration (qtdemux, &duration) ||
8107 duration == GST_CLOCK_TIME_NONE) {
8108 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
8112 for (i = 0; i < qtdemux->n_streams; i++) {
8113 switch (qtdemux->streams[i]->subtype) {
8116 /* retrieve bitrate, prefer avg then max */
8118 if (qtdemux->streams[i]->pending_tags) {
8119 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
8120 GST_TAG_MAXIMUM_BITRATE, &bitrate);
8121 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
8122 GST_TAG_BITRATE, &bitrate);
8125 sum_bitrate += bitrate;
8128 GST_DEBUG_OBJECT (qtdemux,
8129 ">1 stream with unknown bitrate - bailing");
8132 stream = qtdemux->streams[i];
8136 /* For other subtypes, we assume no significant impact on bitrate */
8142 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
8146 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
8148 if (sys_bitrate < sum_bitrate) {
8149 /* This can happen, since sum_bitrate might be derived from maximum
8150 * bitrates and not average bitrates */
8151 GST_DEBUG_OBJECT (qtdemux,
8152 "System bitrate less than sum bitrate - bailing");
8156 bitrate = sys_bitrate - sum_bitrate;
8157 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
8158 ", Stream bitrate = %u", sys_bitrate, bitrate);
8160 if (!stream->pending_tags)
8161 stream->pending_tags = gst_tag_list_new_empty ();
8163 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
8164 GST_TAG_BITRATE, bitrate, NULL);
8167 static GstFlowReturn
8168 qtdemux_prepare_streams (GstQTDemux * qtdemux)
8171 GstFlowReturn ret = GST_FLOW_OK;
8173 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
8175 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
8176 QtDemuxStream *stream = qtdemux->streams[i];
8177 guint32 sample_num = 0;
8181 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
8182 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
8184 if (qtdemux->fragmented) {
8185 /* need all moov samples first */
8186 GST_OBJECT_LOCK (qtdemux);
8187 while (stream->n_samples == 0)
8188 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
8190 GST_OBJECT_UNLOCK (qtdemux);
8192 /* discard any stray moof */
8193 qtdemux->moof_offset = 0;
8196 /* prepare braking */
8197 if (ret != GST_FLOW_ERROR)
8200 /* in pull mode, we should have parsed some sample info by now;
8201 * and quite some code will not handle no samples.
8202 * in push mode, we'll just have to deal with it */
8203 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
8204 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
8205 gst_qtdemux_stream_free (qtdemux, stream);
8206 memmove (&(qtdemux->streams[i]), &(qtdemux->streams[i + 1]),
8207 sizeof (QtDemuxStream *) * (GST_QTDEMUX_MAX_STREAMS - i - 1));
8208 qtdemux->streams[GST_QTDEMUX_MAX_STREAMS - 1] = NULL;
8209 qtdemux->n_streams--;
8214 /* parse number of initial sample to set frame rate cap */
8215 while (sample_num < stream->n_samples && sample_num < samples) {
8216 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
8220 /* collect and sort durations */
8221 samples = MIN (stream->stbl_index + 1, samples);
8222 GST_DEBUG_OBJECT (qtdemux, "%d samples for framerate", samples);
8224 durations = g_array_sized_new (FALSE, FALSE, sizeof (guint32), samples);
8226 while (sample_num < samples) {
8227 g_array_append_val (durations, stream->samples[sample_num].duration);
8230 g_array_sort (durations, less_than);
8231 stream->min_duration = g_array_index (durations, guint32, samples / 2);
8232 g_array_free (durations, TRUE);
8239 static GstFlowReturn
8240 qtdemux_expose_streams (GstQTDemux * qtdemux)
8243 GstFlowReturn ret = GST_FLOW_OK;
8244 GSList *oldpads = NULL;
8247 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
8249 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
8250 QtDemuxStream *stream = qtdemux->streams[i];
8251 GstPad *oldpad = stream->pad;
8254 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
8255 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
8257 /* now we have all info and can expose */
8258 list = stream->pending_tags;
8259 stream->pending_tags = NULL;
8261 oldpads = g_slist_prepend (oldpads, oldpad);
8262 gst_qtdemux_add_stream (qtdemux, stream, list);
8265 gst_qtdemux_guess_bitrate (qtdemux);
8267 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
8269 for (iter = oldpads; iter; iter = g_slist_next (iter)) {
8270 GstPad *oldpad = iter->data;
8272 gst_pad_push_event (oldpad, gst_event_new_eos ());
8273 gst_pad_set_active (oldpad, FALSE);
8274 gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
8275 gst_object_unref (oldpad);
8278 /* check if we should post a redirect in case there is a single trak
8279 * and it is a redirecting trak */
8280 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
8283 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
8284 "an external content");
8285 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
8286 gst_structure_new ("redirect",
8287 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
8289 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
8290 qtdemux->posted_redirect = TRUE;
8293 qtdemux->exposed = TRUE;
8297 /* check if major or compatible brand is 3GP */
8298 static inline gboolean
8299 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
8302 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
8303 GST_MAKE_FOURCC ('3', 'g', 0, 0));
8304 } else if (qtdemux->comp_brands != NULL) {
8308 gboolean res = FALSE;
8310 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
8314 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
8315 GST_MAKE_FOURCC ('3', 'g', 0, 0));
8319 gst_buffer_unmap (qtdemux->comp_brands, &map);
8326 /* check if tag is a spec'ed 3GP tag keyword storing a string */
8327 static inline gboolean
8328 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
8330 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
8331 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
8332 || fourcc == FOURCC_albm;
8336 qtdemux_tag_add_location (GstQTDemux * qtdemux, const char *tag,
8337 const char *dummy, GNode * node)
8339 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
8343 gdouble longitude, latitude, altitude;
8346 len = QT_UINT32 (node->data);
8353 /* TODO: language code skipped */
8355 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
8358 /* do not alarm in trivial case, but bail out otherwise */
8359 if (*(data + offset) != 0) {
8360 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
8364 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8365 GST_TAG_GEO_LOCATION_NAME, name, NULL);
8366 offset += strlen (name);
8370 if (len < offset + 2 + 4 + 4 + 4)
8373 /* +1 +1 = skip null-terminator and location role byte */
8375 /* table in spec says unsigned, semantics say negative has meaning ... */
8376 longitude = QT_SFP32 (data + offset);
8379 latitude = QT_SFP32 (data + offset);
8382 altitude = QT_SFP32 (data + offset);
8384 /* one invalid means all are invalid */
8385 if (longitude >= -180.0 && longitude <= 180.0 &&
8386 latitude >= -90.0 && latitude <= 90.0) {
8387 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8388 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
8389 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
8390 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
8393 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
8400 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
8407 qtdemux_tag_add_year (GstQTDemux * qtdemux, const char *tag, const char *dummy,
8414 len = QT_UINT32 (node->data);
8418 y = QT_UINT16 ((guint8 *) node->data + 12);
8420 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
8423 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
8425 date = g_date_new_dmy (1, 1, y);
8426 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, date, NULL);
8431 qtdemux_tag_add_classification (GstQTDemux * qtdemux, const char *tag,
8432 const char *dummy, GNode * node)
8435 char *tag_str = NULL;
8440 len = QT_UINT32 (node->data);
8445 entity = (guint8 *) node->data + offset;
8446 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
8447 GST_DEBUG_OBJECT (qtdemux,
8448 "classification info: %c%c%c%c invalid classification entity",
8449 entity[0], entity[1], entity[2], entity[3]);
8454 table = QT_UINT16 ((guint8 *) node->data + offset);
8456 /* Language code skipped */
8460 /* Tag format: "XXXX://Y[YYYY]/classification info string"
8461 * XXXX: classification entity, fixed length 4 chars.
8462 * Y[YYYY]: classification table, max 5 chars.
8464 tag_str = g_strdup_printf ("----://%u/%s",
8465 table, (char *) node->data + offset);
8467 /* memcpy To be sure we're preserving byte order */
8468 memcpy (tag_str, entity, 4);
8469 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
8471 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_APPEND, tag,
8481 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
8487 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, const char *tag,
8488 const char *dummy, GNode * node)
8490 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
8496 gboolean ret = TRUE;
8498 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8500 len = QT_UINT32 (data->data);
8501 type = QT_UINT32 ((guint8 *) data->data + 8);
8502 if (type == 0x00000001 && len > 16) {
8503 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
8506 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
8507 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s,
8511 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
8515 len = QT_UINT32 (node->data);
8516 type = QT_UINT32 ((guint8 *) node->data + 4);
8517 if ((type >> 24) == 0xa9) {
8518 /* Type starts with the (C) symbol, so the next 32 bits are
8519 * the language code, which we ignore */
8521 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
8522 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
8523 QT_FOURCC ((guint8 *) node->data + 4))) {
8524 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
8526 /* we go for 3GP style encoding if major brands claims so,
8527 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
8528 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
8529 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
8530 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
8532 /* 16-bit Language code is ignored here as well */
8533 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
8540 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
8541 ret = FALSE; /* may have to fallback */
8543 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
8544 len - offset, env_vars);
8546 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
8547 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s, NULL);
8551 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
8558 qtdemux_tag_add_str (GstQTDemux * qtdemux, const char *tag,
8559 const char *dummy, GNode * node)
8561 qtdemux_tag_add_str_full (qtdemux, tag, dummy, node);
8565 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, const char *tag,
8566 const char *dummy, GNode * node)
8568 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
8570 char *s, *t, *k = NULL;
8575 /* first try normal string tag if major brand not 3GP */
8576 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
8577 if (!qtdemux_tag_add_str_full (qtdemux, tag, dummy, node)) {
8578 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
8579 * let's try it 3gpp way after minor safety check */
8581 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
8587 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
8591 len = QT_UINT32 (data);
8595 count = QT_UINT8 (data + 14);
8597 for (; count; count--) {
8600 if (offset + 1 > len)
8602 slen = QT_UINT8 (data + offset);
8604 if (offset + slen > len)
8606 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
8609 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
8611 t = g_strjoin (",", k, s, NULL);
8619 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
8626 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
8627 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, k, NULL);
8636 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
8642 qtdemux_tag_add_num (GstQTDemux * qtdemux, const char *tag1,
8643 const char *tag2, GNode * node)
8650 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8652 len = QT_UINT32 (data->data);
8653 type = QT_UINT32 ((guint8 *) data->data + 8);
8654 if (type == 0x00000000 && len >= 22) {
8655 n1 = QT_UINT16 ((guint8 *) data->data + 18);
8656 n2 = QT_UINT16 ((guint8 *) data->data + 20);
8658 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
8659 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8663 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
8664 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8672 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
8680 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8682 len = QT_UINT32 (data->data);
8683 type = QT_UINT32 ((guint8 *) data->data + 8);
8684 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
8685 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
8686 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
8687 n1 = QT_UINT16 ((guint8 *) data->data + 16);
8689 /* do not add bpm=0 */
8690 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
8691 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8692 tag1, (gdouble) n1, NULL);
8699 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, const char *tag1,
8700 const char *dummy, GNode * node)
8707 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8709 len = QT_UINT32 (data->data);
8710 type = QT_UINT32 ((guint8 *) data->data + 8);
8711 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
8712 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
8713 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
8714 num = QT_UINT32 ((guint8 *) data->data + 16);
8716 /* do not add num=0 */
8717 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
8718 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8726 qtdemux_tag_add_covr (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
8734 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8736 len = QT_UINT32 (data->data);
8737 type = QT_UINT32 ((guint8 *) data->data + 8);
8738 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
8739 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
8741 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
8742 len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
8743 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
8744 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8745 tag1, sample, NULL);
8746 gst_sample_unref (sample);
8753 qtdemux_tag_add_date (GstQTDemux * qtdemux, const char *tag, const char *dummy,
8761 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8763 len = QT_UINT32 (data->data);
8764 type = QT_UINT32 ((guint8 *) data->data + 8);
8765 if (type == 0x00000001 && len > 16) {
8766 guint y, m = 1, d = 1;
8769 s = g_strndup ((char *) data->data + 16, len - 16);
8770 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
8771 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
8772 if (ret >= 1 && y > 1500 && y < 3000) {
8775 date = g_date_new_dmy (d, m, y);
8776 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag,
8780 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
8788 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, const char *tag, const char *dummy,
8793 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8795 /* re-route to normal string tag if major brand says so
8796 * or no data atom and compatible brand suggests so */
8797 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
8798 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
8799 qtdemux_tag_add_str (qtdemux, tag, dummy, node);
8806 len = QT_UINT32 (data->data);
8807 type = QT_UINT32 ((guint8 *) data->data + 8);
8808 if (type == 0x00000000 && len >= 18) {
8809 n = QT_UINT16 ((guint8 *) data->data + 16);
8813 genre = gst_tag_id3_genre_get (n - 1);
8814 if (genre != NULL) {
8815 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
8816 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8825 qtdemux_add_double_tag_from_str (GstQTDemux * demux, const gchar * tag,
8826 guint8 * data, guint32 datasize)
8831 /* make a copy to have \0 at the end */
8832 datacopy = g_strndup ((gchar *) data, datasize);
8834 /* convert the str to double */
8835 if (sscanf (datacopy, "%lf", &value) == 1) {
8836 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
8837 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_REPLACE, tag, value, NULL);
8839 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
8847 qtdemux_tag_add_revdns (GstQTDemux * demux, const char *tag,
8848 const char *tag_bis, GNode * node)
8857 const gchar *meanstr;
8858 const gchar *namestr;
8860 /* checking the whole ---- atom size for consistency */
8861 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
8862 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
8866 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
8868 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
8872 meansize = QT_UINT32 (mean->data);
8873 if (meansize <= 12) {
8874 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
8877 meanstr = ((gchar *) mean->data) + 12;
8879 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
8881 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
8885 namesize = QT_UINT32 (name->data);
8886 if (namesize <= 12) {
8887 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
8890 namestr = ((gchar *) name->data) + 12;
8897 * uint24 - data type
8901 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8903 GST_WARNING_OBJECT (demux, "No data atom in this tag");
8906 datasize = QT_UINT32 (data->data);
8907 if (datasize <= 16) {
8908 GST_WARNING_OBJECT (demux, "Data atom too small");
8911 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
8913 if (strncmp (meanstr, "com.apple.iTunes", meansize - 12) == 0) {
8916 const gchar name[28];
8917 const gchar tag[28];
8920 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
8921 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
8922 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
8923 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
8924 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
8925 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
8926 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
8927 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
8931 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
8932 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize - 12)) {
8933 switch (gst_tag_get_type (tags[i].tag)) {
8935 qtdemux_add_double_tag_from_str (demux, tags[i].tag,
8936 ((guint8 *) data->data) + 16, datasize - 16);
8939 qtdemux_tag_add_str (demux, tags[i].tag, NULL, node);
8948 if (i == G_N_ELEMENTS (tags))
8962 meanstr_dbg = g_strndup (meanstr, meansize - 12);
8963 namestr_dbg = g_strndup (namestr, namesize - 12);
8965 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
8966 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
8968 g_free (namestr_dbg);
8969 g_free (meanstr_dbg);
8975 qtdemux_tag_add_id32 (GstQTDemux * demux, const char *tag,
8976 const char *tag_bis, GNode * node)
8981 GstTagList *taglist = NULL;
8983 GST_LOG_OBJECT (demux, "parsing ID32");
8986 len = GST_READ_UINT32_BE (data);
8988 /* need at least full box and language tag */
8992 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
8993 gst_buffer_fill (buf, 0, data + 14, len - 14);
8995 taglist = gst_tag_list_from_id3v2_tag (buf);
8997 GST_LOG_OBJECT (demux, "parsing ok");
8998 gst_tag_list_insert (demux->tag_list, taglist, GST_TAG_MERGE_KEEP);
9000 GST_LOG_OBJECT (demux, "parsing failed");
9004 gst_tag_list_unref (taglist);
9006 gst_buffer_unref (buf);
9009 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux,
9010 const char *tag, const char *tag_bis, GNode * node);
9013 FOURCC_pcst -> if media is a podcast -> bool
9014 FOURCC_cpil -> if media is part of a compilation -> bool
9015 FOURCC_pgap -> if media is part of a gapless context -> bool
9016 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
9022 const gchar *gst_tag;
9023 const gchar *gst_tag_bis;
9024 const GstQTDemuxAddTagFunc func;
9027 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
9028 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
9029 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
9030 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
9031 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
9032 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
9033 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
9034 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
9035 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
9036 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
9037 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
9038 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
9039 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
9040 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
9041 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
9042 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
9043 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
9044 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
9045 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
9046 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
9047 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
9048 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
9049 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
9050 qtdemux_tag_add_num}, {
9051 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
9052 qtdemux_tag_add_num}, {
9053 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
9054 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
9055 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
9056 FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
9057 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
9058 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
9059 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
9060 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
9061 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
9062 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
9063 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
9064 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
9065 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
9066 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
9067 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
9068 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
9069 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
9070 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
9071 qtdemux_tag_add_classification}, {
9073 /* This is a special case, some tags are stored in this
9074 * 'reverse dns naming', according to:
9075 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
9078 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
9079 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
9080 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
9084 qtdemux_tag_add_blob (GNode * node, GstQTDemux * demux)
9097 len = QT_UINT32 (data);
9098 buf = gst_buffer_new_and_alloc (len);
9099 _gst_buffer_copy_into_mem (buf, 0, data, len);
9101 /* heuristic to determine style of tag */
9102 if (QT_FOURCC (data + 4) == FOURCC_____ ||
9103 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
9105 else if (demux->major_brand == FOURCC_qt__)
9106 style = "quicktime";
9107 /* fall back to assuming iso/3gp tag style */
9111 /* santize the name for the caps. */
9112 for (i = 0; i < 4; i++) {
9113 guint8 d = data[4 + i];
9114 if (g_ascii_isalnum (d))
9115 ndata[i] = g_ascii_tolower (d);
9120 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
9121 ndata[0], ndata[1], ndata[2], ndata[3]);
9122 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
9124 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
9125 sample = gst_sample_new (buf, NULL, NULL, s);
9126 gst_buffer_unref (buf);
9127 g_free (media_type);
9129 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
9132 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_APPEND,
9133 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
9135 gst_sample_unref (sample);
9139 qtdemux_parse_udta (GstQTDemux * qtdemux, GNode * udta)
9147 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
9149 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
9151 GST_LOG_OBJECT (qtdemux, "no ilst");
9156 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
9159 GST_DEBUG_OBJECT (qtdemux, "new tag list");
9160 if (!qtdemux->tag_list) {
9161 qtdemux->tag_list = gst_tag_list_new_empty ();
9162 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
9166 while (i < G_N_ELEMENTS (add_funcs)) {
9167 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
9171 len = QT_UINT32 (node->data);
9173 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
9174 GST_FOURCC_ARGS (add_funcs[i].fourcc));
9176 add_funcs[i].func (qtdemux, add_funcs[i].gst_tag,
9177 add_funcs[i].gst_tag_bis, node);
9179 g_node_destroy (node);
9185 /* parsed nodes have been removed, pass along remainder as blob */
9186 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
9187 (GNodeForeachFunc) qtdemux_tag_add_blob, qtdemux);
9189 /* parse up XMP_ node if existing */
9190 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
9193 GstTagList *taglist;
9195 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
9196 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
9197 taglist = gst_tag_list_from_xmp_buffer (buf);
9198 gst_buffer_unref (buf);
9200 qtdemux_handle_xmp_taglist (qtdemux, taglist);
9202 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
9209 GstStructure *structure; /* helper for sort function */
9211 guint min_req_bitrate;
9212 guint min_req_qt_version;
9216 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
9218 GstQtReference *ref_a = (GstQtReference *) a;
9219 GstQtReference *ref_b = (GstQtReference *) b;
9221 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
9222 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
9224 /* known bitrates go before unknown; higher bitrates go first */
9225 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
9228 /* sort the redirects and post a message for the application.
9231 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
9233 GstQtReference *best;
9236 GValue list_val = { 0, };
9239 g_assert (references != NULL);
9241 references = g_list_sort (references, qtdemux_redirects_sort_func);
9243 best = (GstQtReference *) references->data;
9245 g_value_init (&list_val, GST_TYPE_LIST);
9247 for (l = references; l != NULL; l = l->next) {
9248 GstQtReference *ref = (GstQtReference *) l->data;
9249 GValue struct_val = { 0, };
9251 ref->structure = gst_structure_new ("redirect",
9252 "new-location", G_TYPE_STRING, ref->location, NULL);
9254 if (ref->min_req_bitrate > 0) {
9255 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
9256 ref->min_req_bitrate, NULL);
9259 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
9260 g_value_set_boxed (&struct_val, ref->structure);
9261 gst_value_list_append_value (&list_val, &struct_val);
9262 g_value_unset (&struct_val);
9263 /* don't free anything here yet, since we need best->structure below */
9266 g_assert (best != NULL);
9267 s = gst_structure_copy (best->structure);
9269 if (g_list_length (references) > 1) {
9270 gst_structure_set_value (s, "locations", &list_val);
9273 g_value_unset (&list_val);
9275 for (l = references; l != NULL; l = l->next) {
9276 GstQtReference *ref = (GstQtReference *) l->data;
9278 gst_structure_free (ref->structure);
9279 g_free (ref->location);
9282 g_list_free (references);
9284 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
9285 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
9286 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
9287 qtdemux->posted_redirect = TRUE;
9290 /* look for redirect nodes, collect all redirect information and
9294 qtdemux_parse_redirects (GstQTDemux * qtdemux)
9296 GNode *rmra, *rmda, *rdrf;
9298 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
9300 GList *redirects = NULL;
9302 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
9304 GstQtReference ref = { NULL, NULL, 0, 0 };
9307 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
9308 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
9309 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
9310 ref.min_req_bitrate);
9313 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
9314 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
9315 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
9317 #ifndef GST_DISABLE_GST_DEBUG
9318 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
9320 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
9322 GST_LOG_OBJECT (qtdemux,
9323 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
9324 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
9325 bitmask, check_type);
9326 if (package == FOURCC_qtim && check_type == 0) {
9327 ref.min_req_qt_version = version;
9331 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
9336 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
9337 ref_data = (guint8 *) rdrf->data + 20;
9338 if (ref_type == FOURCC_alis) {
9339 guint record_len, record_version, fn_len;
9341 /* MacOSX alias record, google for alias-layout.txt */
9342 record_len = QT_UINT16 (ref_data + 4);
9343 record_version = QT_UINT16 (ref_data + 4 + 2);
9344 fn_len = QT_UINT8 (ref_data + 50);
9345 if (record_len > 50 && record_version == 2 && fn_len > 0) {
9346 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
9348 } else if (ref_type == FOURCC_url_) {
9349 ref.location = g_strdup ((gchar *) ref_data);
9351 GST_DEBUG_OBJECT (qtdemux,
9352 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
9353 GST_FOURCC_ARGS (ref_type));
9355 if (ref.location != NULL) {
9356 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
9357 redirects = g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
9359 GST_WARNING_OBJECT (qtdemux,
9360 "Failed to extract redirect location from rdrf atom");
9364 /* look for others */
9365 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
9368 if (redirects != NULL) {
9369 qtdemux_process_redirects (qtdemux, redirects);
9376 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
9381 tags = gst_tag_list_new_empty ();
9382 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
9385 if (qtdemux->major_brand == FOURCC_mjp2)
9386 fmt = "Motion JPEG 2000";
9387 else if ((qtdemux->major_brand & 0xffff) == GST_MAKE_FOURCC ('3', 'g', 0, 0))
9389 else if (qtdemux->major_brand == FOURCC_qt__)
9391 else if (qtdemux->fragmented)
9394 fmt = "ISO MP4/M4A";
9396 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
9397 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
9399 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
9405 /* we have read th complete moov node now.
9406 * This function parses all of the relevant info, creates the traks and
9407 * prepares all data structures for playback
9410 qtdemux_parse_tree (GstQTDemux * qtdemux)
9417 guint64 creation_time;
9418 GstDateTime *datetime = NULL;
9421 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
9423 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
9424 return qtdemux_parse_redirects (qtdemux);
9427 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
9429 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
9430 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
9431 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
9432 } else if (version == 0) {
9433 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
9434 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
9435 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
9437 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
9441 /* Moving qt creation time (secs since 1904) to unix time */
9442 if (creation_time != 0) {
9443 if (creation_time > QTDEMUX_SECONDS_FROM_1904_TO_1970) {
9446 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
9447 /* some data cleansing sanity */
9448 g_get_current_time (&now);
9449 if (now.tv_sec + 24 * 3600 < creation_time) {
9450 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
9452 datetime = gst_date_time_new_from_unix_epoch_local_time (creation_time);
9455 GST_WARNING_OBJECT (qtdemux, "Can't handle datetimes before 1970 yet, "
9456 "please file a bug at http://bugzilla.gnome.org");
9460 if (!qtdemux->tag_list) {
9461 qtdemux->tag_list = gst_tag_list_new_empty ();
9462 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
9465 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
9466 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
9468 gst_date_time_unref (datetime);
9471 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
9472 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
9474 /* check for fragmented file and get some (default) data */
9475 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
9478 GstByteReader mehd_data;
9480 /* let track parsing or anyone know weird stuff might happen ... */
9481 qtdemux->fragmented = TRUE;
9483 /* compensate for total duration */
9484 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
9486 qtdemux_parse_mehd (qtdemux, &mehd_data);
9489 /* set duration in the segment info */
9490 gst_qtdemux_get_duration (qtdemux, &duration);
9492 qtdemux->segment.duration = duration;
9493 /* also do not exceed duration; stop is set that way post seek anyway,
9494 * and segment activation falls back to duration,
9495 * whereas loop only checks stop, so let's align this here as well */
9496 qtdemux->segment.stop = duration;
9499 /* parse all traks */
9500 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
9502 qtdemux_parse_trak (qtdemux, trak);
9503 /* iterate all siblings */
9504 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
9508 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
9510 qtdemux_parse_udta (qtdemux, udta);
9512 GST_LOG_OBJECT (qtdemux, "No udta node found.");
9515 /* maybe also some tags in meta box */
9516 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
9518 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
9519 qtdemux_parse_udta (qtdemux, udta);
9521 GST_LOG_OBJECT (qtdemux, "No meta node found.");
9524 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
9529 /* taken from ffmpeg */
9531 get_size (guint8 * ptr, guint8 ** end)
9540 len = (len << 7) | (c & 0x7f);
9549 /* this can change the codec originally present in @list */
9551 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
9552 GNode * esds, GstTagList * list)
9554 int len = QT_UINT32 (esds->data);
9555 guint8 *ptr = esds->data;
9556 guint8 *end = ptr + len;
9558 guint8 *data_ptr = NULL;
9560 guint8 object_type_id = 0;
9561 const char *codec_name = NULL;
9562 GstCaps *caps = NULL;
9564 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
9566 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
9569 tag = QT_UINT8 (ptr);
9570 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
9572 len = get_size (ptr, &ptr);
9573 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
9577 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
9578 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
9582 guint max_bitrate, avg_bitrate;
9584 object_type_id = QT_UINT8 (ptr);
9585 max_bitrate = QT_UINT32 (ptr + 5);
9586 avg_bitrate = QT_UINT32 (ptr + 9);
9587 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
9588 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
9589 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
9590 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
9591 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
9592 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
9593 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
9594 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
9596 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
9597 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
9604 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
9610 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
9614 GST_ERROR_OBJECT (qtdemux, "parse error");
9619 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
9620 * in use, and should also be used to override some other parameters for some
9622 switch (object_type_id) {
9623 case 0x20: /* MPEG-4 */
9624 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
9625 * profile_and_level_indication */
9626 if (data_ptr != NULL && data_len >= 5 &&
9627 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
9628 gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
9629 data_ptr + 4, data_len - 4);
9631 break; /* Nothing special needed here */
9632 case 0x21: /* H.264 */
9633 codec_name = "H.264 / AVC";
9634 caps = gst_caps_new_simple ("video/x-h264",
9635 "stream-format", G_TYPE_STRING, "avc",
9636 "alignment", G_TYPE_STRING, "au", NULL);
9638 case 0x40: /* AAC (any) */
9639 case 0x66: /* AAC Main */
9640 case 0x67: /* AAC LC */
9641 case 0x68: /* AAC SSR */
9642 /* Override channels and rate based on the codec_data, as it's often
9644 /* Only do so for basic setup without HE-AAC extension */
9645 if (data_ptr && data_len == 2) {
9646 guint channels, rateindex, rate;
9648 /* FIXME: add gst_codec_utils_aac_get_{channels|sample_rate}()? */
9649 channels = (data_ptr[1] & 0x7f) >> 3;
9650 if (channels > 0 && channels < 7) {
9651 stream->n_channels = channels;
9652 } else if (channels == 7) {
9653 stream->n_channels = 8;
9656 rateindex = ((data_ptr[0] & 0x7) << 1) | ((data_ptr[1] & 0x80) >> 7);
9657 rate = gst_codec_utils_aac_get_sample_rate_from_index (rateindex);
9659 stream->rate = rate;
9662 /* Set level and profile if possible */
9663 if (data_ptr != NULL && data_len >= 2) {
9664 gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
9665 data_ptr, data_len);
9668 case 0x60: /* MPEG-2, various profiles */
9674 codec_name = "MPEG-2 video";
9676 gst_caps_unref (stream->caps);
9677 stream->caps = gst_caps_new_simple ("video/mpeg",
9678 "mpegversion", G_TYPE_INT, 2,
9679 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9681 case 0x69: /* MP3 has two different values, accept either */
9683 /* change to mpeg1 layer 3 audio */
9684 gst_caps_set_simple (stream->caps, "layer", G_TYPE_INT, 3,
9685 "mpegversion", G_TYPE_INT, 1, NULL);
9686 codec_name = "MPEG-1 layer 3";
9688 case 0x6A: /* MPEG-1 */
9689 codec_name = "MPEG-1 video";
9691 gst_caps_unref (stream->caps);
9692 stream->caps = gst_caps_new_simple ("video/mpeg",
9693 "mpegversion", G_TYPE_INT, 1,
9694 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9696 case 0x6C: /* MJPEG */
9697 caps = gst_caps_new_empty_simple ("image/jpeg");
9698 codec_name = "Motion-JPEG";
9700 case 0x6D: /* PNG */
9701 caps = gst_caps_new_empty_simple ("image/png");
9702 codec_name = "PNG still images";
9704 case 0x6E: /* JPEG2000 */
9705 codec_name = "JPEG-2000";
9706 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
9708 case 0xA4: /* Dirac */
9709 codec_name = "Dirac";
9710 caps = gst_caps_new_empty_simple ("video/x-dirac");
9712 case 0xA5: /* AC3 */
9713 codec_name = "AC-3 audio";
9714 caps = gst_caps_new_simple ("audio/x-ac3",
9715 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
9717 case 0xE1: /* QCELP */
9718 /* QCELP, the codec_data is a riff tag (little endian) with
9719 * 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). */
9720 caps = gst_caps_new_empty_simple ("audio/qcelp");
9721 codec_name = "QCELP";
9727 /* If we have a replacement caps, then change our caps for this stream */
9729 gst_caps_unref (stream->caps);
9730 stream->caps = caps;
9733 if (codec_name && list)
9734 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
9735 GST_TAG_AUDIO_CODEC, codec_name, NULL);
9737 /* Add the codec_data attribute to caps, if we have it */
9741 buffer = gst_buffer_new_and_alloc (data_len);
9742 _gst_buffer_copy_into_mem (buffer, 0, data_ptr, data_len);
9744 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
9745 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
9747 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
9749 gst_buffer_unref (buffer);
9754 #define _codec(name) \
9757 *codec_name = g_strdup (name); \
9762 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
9763 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
9766 const GstStructure *s;
9770 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
9771 _codec ("PNG still images");
9772 caps = gst_caps_new_empty_simple ("image/png");
9774 case GST_MAKE_FOURCC ('j', 'p', 'e', 'g'):
9775 _codec ("JPEG still images");
9776 caps = gst_caps_new_empty_simple ("image/jpeg");
9778 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
9779 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
9780 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
9781 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
9782 _codec ("Motion-JPEG");
9783 caps = gst_caps_new_empty_simple ("image/jpeg");
9785 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
9786 _codec ("Motion-JPEG format B");
9787 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
9789 case GST_MAKE_FOURCC ('m', 'j', 'p', '2'):
9790 _codec ("JPEG-2000");
9791 /* override to what it should be according to spec, avoid palette_data */
9792 stream->bits_per_sample = 24;
9793 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
9795 case GST_MAKE_FOURCC ('S', 'V', 'Q', '3'):
9796 _codec ("Sorensen video v.3");
9797 caps = gst_caps_new_simple ("video/x-svq",
9798 "svqversion", G_TYPE_INT, 3, NULL);
9800 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
9801 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
9802 _codec ("Sorensen video v.1");
9803 caps = gst_caps_new_simple ("video/x-svq",
9804 "svqversion", G_TYPE_INT, 1, NULL);
9806 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
9810 _codec ("Raw RGB video");
9811 bps = QT_UINT16 (stsd_data + 98);
9812 /* set common stuff */
9813 caps = gst_caps_new_empty_simple ("video/x-raw");
9817 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB15", NULL);
9820 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB16", NULL);
9823 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB", NULL);
9826 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "ARGB", NULL);
9834 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
9835 _codec ("Raw planar YUV 4:2:0");
9836 caps = gst_caps_new_simple ("video/x-raw",
9837 "format", G_TYPE_STRING, "I420", NULL);
9839 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
9840 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
9841 _codec ("Raw packed YUV 4:2:2");
9842 caps = gst_caps_new_simple ("video/x-raw",
9843 "format", G_TYPE_STRING, "YUY2", NULL);
9845 case GST_MAKE_FOURCC ('2', 'v', 'u', 'y'):
9846 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
9847 _codec ("Raw packed YUV 4:2:2");
9848 caps = gst_caps_new_simple ("video/x-raw",
9849 "format", G_TYPE_STRING, "UYVY", NULL);
9851 case GST_MAKE_FOURCC ('v', '2', '1', '0'):
9852 _codec ("Raw packed YUV 10-bit 4:2:2");
9853 caps = gst_caps_new_simple ("video/x-raw",
9854 "format", G_TYPE_STRING, "v210", NULL);
9856 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
9857 _codec ("Raw packed RGB 10-bit 4:4:4");
9858 caps = gst_caps_new_simple ("video/x-raw",
9859 "format", G_TYPE_STRING, "r210", NULL);
9861 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
9862 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
9863 _codec ("MPEG-1 video");
9864 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
9865 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9867 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
9868 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
9869 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
9870 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
9871 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080i60 */
9872 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
9873 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
9874 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
9875 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
9876 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
9877 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
9878 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 */
9879 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
9880 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
9881 _codec ("MPEG-2 video");
9882 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
9883 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9885 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
9886 _codec ("GIF still images");
9887 caps = gst_caps_new_empty_simple ("image/gif");
9889 case GST_MAKE_FOURCC ('h', '2', '6', '3'):
9890 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
9891 case GST_MAKE_FOURCC ('s', '2', '6', '3'):
9892 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
9894 /* ffmpeg uses the height/width props, don't know why */
9895 caps = gst_caps_new_simple ("video/x-h263",
9896 "variant", G_TYPE_STRING, "itu", NULL);
9898 case GST_MAKE_FOURCC ('m', 'p', '4', 'v'):
9899 case GST_MAKE_FOURCC ('M', 'P', '4', 'V'):
9900 _codec ("MPEG-4 video");
9901 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
9902 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9904 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
9905 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
9906 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
9907 caps = gst_caps_new_simple ("video/x-msmpeg",
9908 "msmpegversion", G_TYPE_INT, 43, NULL);
9910 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
9912 caps = gst_caps_new_simple ("video/x-divx",
9913 "divxversion", G_TYPE_INT, 3, NULL);
9915 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
9916 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
9918 caps = gst_caps_new_simple ("video/x-divx",
9919 "divxversion", G_TYPE_INT, 4, NULL);
9921 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
9923 caps = gst_caps_new_simple ("video/x-divx",
9924 "divxversion", G_TYPE_INT, 5, NULL);
9927 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
9928 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
9929 case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
9930 case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
9931 case GST_MAKE_FOURCC ('F', 'M', 'P', '4'):
9932 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
9933 caps = gst_caps_new_simple ("video/mpeg",
9934 "mpegversion", G_TYPE_INT, 4, NULL);
9936 *codec_name = g_strdup ("MPEG-4");
9939 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
9941 caps = gst_caps_new_empty_simple ("video/x-cinepak");
9943 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
9944 _codec ("Apple QuickDraw");
9945 caps = gst_caps_new_empty_simple ("video/x-qdrw");
9947 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
9948 _codec ("Apple video");
9949 caps = gst_caps_new_empty_simple ("video/x-apple-video");
9951 case GST_MAKE_FOURCC ('a', 'v', 'c', '1'):
9952 _codec ("H.264 / AVC");
9953 caps = gst_caps_new_simple ("video/x-h264",
9954 "stream-format", G_TYPE_STRING, "avc",
9955 "alignment", G_TYPE_STRING, "au", NULL);
9957 case GST_MAKE_FOURCC ('r', 'l', 'e', ' '):
9958 _codec ("Run-length encoding");
9959 caps = gst_caps_new_simple ("video/x-rle",
9960 "layout", G_TYPE_STRING, "quicktime", NULL);
9962 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
9963 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
9964 _codec ("Indeo Video 3");
9965 caps = gst_caps_new_simple ("video/x-indeo",
9966 "indeoversion", G_TYPE_INT, 3, NULL);
9968 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
9969 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
9970 _codec ("Intel Video 4");
9971 caps = gst_caps_new_simple ("video/x-indeo",
9972 "indeoversion", G_TYPE_INT, 4, NULL);
9974 case GST_MAKE_FOURCC ('d', 'v', 'c', 'p'):
9975 case GST_MAKE_FOURCC ('d', 'v', 'c', ' '):
9976 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
9977 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
9978 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
9979 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
9980 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
9981 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
9982 _codec ("DV Video");
9983 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
9984 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9986 case GST_MAKE_FOURCC ('d', 'v', '5', 'n'): /* DVCPRO50 NTSC */
9987 case GST_MAKE_FOURCC ('d', 'v', '5', 'p'): /* DVCPRO50 PAL */
9988 _codec ("DVCPro50 Video");
9989 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
9990 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9992 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
9993 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
9994 _codec ("DVCProHD Video");
9995 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
9996 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9998 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
9999 _codec ("Apple Graphics (SMC)");
10000 caps = gst_caps_new_empty_simple ("video/x-smc");
10002 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
10004 caps = gst_caps_new_empty_simple ("video/x-vp3");
10006 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
10007 _codec ("VP6 Flash");
10008 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
10010 case GST_MAKE_FOURCC ('X', 'i', 'T', 'h'):
10012 caps = gst_caps_new_empty_simple ("video/x-theora");
10013 /* theora uses one byte of padding in the data stream because it does not
10014 * allow 0 sized packets while theora does */
10015 stream->padding = 1;
10017 case GST_MAKE_FOURCC ('d', 'r', 'a', 'c'):
10019 caps = gst_caps_new_empty_simple ("video/x-dirac");
10021 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
10022 _codec ("TIFF still images");
10023 caps = gst_caps_new_empty_simple ("image/tiff");
10025 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
10026 _codec ("Apple Intermediate Codec");
10027 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
10029 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
10030 _codec ("AVID DNxHD");
10031 caps = gst_caps_from_string ("video/x-dnxhd");
10033 case GST_MAKE_FOURCC ('V', 'P', '8', '0'):
10034 _codec ("On2 VP8");
10035 caps = gst_caps_from_string ("video/x-vp8");
10037 case GST_MAKE_FOURCC ('a', 'p', 'c', 's'):
10038 _codec ("Apple ProRes LT");
10040 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
10043 case GST_MAKE_FOURCC ('a', 'p', 'c', 'h'):
10044 _codec ("Apple ProRes HQ");
10046 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
10049 case GST_MAKE_FOURCC ('a', 'p', 'c', 'n'):
10050 _codec ("Apple ProRes");
10052 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
10055 case GST_MAKE_FOURCC ('a', 'p', 'c', 'o'):
10056 _codec ("Apple ProRes Proxy");
10058 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
10061 case GST_MAKE_FOURCC ('a', 'p', '4', 'h'):
10062 _codec ("Apple ProRes 4444");
10064 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
10069 caps = gst_caps_new_simple ("video/x-wmv",
10070 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
10072 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
10075 char *s, fourstr[5];
10077 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
10078 s = g_strdup_printf ("video/x-gst-fourcc-%s", g_strstrip (fourstr));
10079 caps = gst_caps_new_empty_simple (s);
10084 /* enable clipping for raw video streams */
10085 s = gst_caps_get_structure (caps, 0);
10086 name = gst_structure_get_name (s);
10087 if (g_str_has_prefix (name, "video/x-raw")) {
10088 stream->need_clip = TRUE;
10094 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
10095 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
10098 const GstStructure *s;
10102 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
10105 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
10106 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
10107 _codec ("Raw 8-bit PCM audio");
10108 caps = gst_caps_new_simple ("audio/x-raw",
10109 "format", G_TYPE_STRING, "U8",
10110 "layout", G_TYPE_STRING, "interleaved", NULL);
10112 case GST_MAKE_FOURCC ('t', 'w', 'o', 's'):
10113 endian = G_BIG_ENDIAN;
10115 case GST_MAKE_FOURCC ('s', 'o', 'w', 't'):
10119 GstAudioFormat format;
10122 endian = G_LITTLE_ENDIAN;
10124 depth = stream->bytes_per_packet * 8;
10125 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
10127 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
10131 caps = gst_caps_new_simple ("audio/x-raw",
10132 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
10133 "layout", G_TYPE_STRING, "interleaved", NULL);
10136 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
10137 _codec ("Raw 64-bit floating-point audio");
10138 caps = gst_caps_new_simple ("audio/x-raw",
10139 "format", G_TYPE_STRING, "F64BE",
10140 "layout", G_TYPE_STRING, "interleaved", NULL);
10142 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
10143 _codec ("Raw 32-bit floating-point audio");
10144 caps = gst_caps_new_simple ("audio/x-raw",
10145 "format", G_TYPE_STRING, "F32BE",
10146 "layout", G_TYPE_STRING, "interleaved", NULL);
10149 _codec ("Raw 24-bit PCM audio");
10150 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
10152 caps = gst_caps_new_simple ("audio/x-raw",
10153 "format", G_TYPE_STRING, "S24BE",
10154 "layout", G_TYPE_STRING, "interleaved", NULL);
10156 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
10157 _codec ("Raw 32-bit PCM audio");
10158 caps = gst_caps_new_simple ("audio/x-raw",
10159 "format", G_TYPE_STRING, "S32BE",
10160 "layout", G_TYPE_STRING, "interleaved", NULL);
10162 case GST_MAKE_FOURCC ('u', 'l', 'a', 'w'):
10163 _codec ("Mu-law audio");
10164 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
10166 case GST_MAKE_FOURCC ('a', 'l', 'a', 'w'):
10167 _codec ("A-law audio");
10168 caps = gst_caps_new_empty_simple ("audio/x-alaw");
10172 _codec ("Microsoft ADPCM");
10173 /* Microsoft ADPCM-ACM code 2 */
10174 caps = gst_caps_new_simple ("audio/x-adpcm",
10175 "layout", G_TYPE_STRING, "microsoft", NULL);
10179 _codec ("DVI/IMA ADPCM");
10180 caps = gst_caps_new_simple ("audio/x-adpcm",
10181 "layout", G_TYPE_STRING, "dvi", NULL);
10185 _codec ("DVI/Intel IMA ADPCM");
10186 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
10187 caps = gst_caps_new_simple ("audio/x-adpcm",
10188 "layout", G_TYPE_STRING, "quicktime", NULL);
10192 /* MPEG layer 3, CBR only (pre QT4.1) */
10193 case GST_MAKE_FOURCC ('.', 'm', 'p', '3'):
10194 _codec ("MPEG-1 layer 3");
10195 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
10196 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
10197 "mpegversion", G_TYPE_INT, 1, NULL);
10200 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
10201 _codec ("EAC-3 audio");
10202 caps = gst_caps_new_simple ("audio/x-eac3",
10203 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
10204 stream->sampled = TRUE;
10206 case GST_MAKE_FOURCC ('a', 'c', '-', '3'):
10207 _codec ("AC-3 audio");
10208 caps = gst_caps_new_simple ("audio/x-ac3",
10209 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
10210 stream->sampled = TRUE;
10212 case GST_MAKE_FOURCC ('M', 'A', 'C', '3'):
10214 caps = gst_caps_new_simple ("audio/x-mace",
10215 "maceversion", G_TYPE_INT, 3, NULL);
10217 case GST_MAKE_FOURCC ('M', 'A', 'C', '6'):
10219 caps = gst_caps_new_simple ("audio/x-mace",
10220 "maceversion", G_TYPE_INT, 6, NULL);
10222 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
10224 caps = gst_caps_new_empty_simple ("application/ogg");
10226 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
10227 _codec ("DV audio");
10228 caps = gst_caps_new_empty_simple ("audio/x-dv");
10230 case GST_MAKE_FOURCC ('m', 'p', '4', 'a'):
10231 _codec ("MPEG-4 AAC audio");
10232 caps = gst_caps_new_simple ("audio/mpeg",
10233 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
10234 "stream-format", G_TYPE_STRING, "raw", NULL);
10236 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
10237 _codec ("QDesign Music");
10238 caps = gst_caps_new_empty_simple ("audio/x-qdm");
10240 case GST_MAKE_FOURCC ('Q', 'D', 'M', '2'):
10241 _codec ("QDesign Music v.2");
10242 /* FIXME: QDesign music version 2 (no constant) */
10243 if (FALSE && data) {
10244 caps = gst_caps_new_simple ("audio/x-qdm2",
10245 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
10246 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
10247 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
10249 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
10252 case GST_MAKE_FOURCC ('a', 'g', 's', 'm'):
10253 _codec ("GSM audio");
10254 caps = gst_caps_new_empty_simple ("audio/x-gsm");
10256 case GST_MAKE_FOURCC ('s', 'a', 'm', 'r'):
10257 _codec ("AMR audio");
10258 caps = gst_caps_new_empty_simple ("audio/AMR");
10260 case GST_MAKE_FOURCC ('s', 'a', 'w', 'b'):
10261 _codec ("AMR-WB audio");
10262 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
10264 case GST_MAKE_FOURCC ('i', 'm', 'a', '4'):
10265 _codec ("Quicktime IMA ADPCM");
10266 caps = gst_caps_new_simple ("audio/x-adpcm",
10267 "layout", G_TYPE_STRING, "quicktime", NULL);
10269 case GST_MAKE_FOURCC ('a', 'l', 'a', 'c'):
10270 _codec ("Apple lossless audio");
10271 caps = gst_caps_new_empty_simple ("audio/x-alac");
10273 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
10274 _codec ("QualComm PureVoice");
10275 caps = gst_caps_from_string ("audio/qcelp");
10279 caps = gst_caps_new_empty_simple ("audio/x-wma");
10281 case GST_MAKE_FOURCC ('l', 'p', 'c', 'm'):
10286 GstAudioFormat format;
10289 FLAG_IS_FLOAT = 0x1,
10290 FLAG_IS_BIG_ENDIAN = 0x2,
10291 FLAG_IS_SIGNED = 0x4,
10292 FLAG_IS_PACKED = 0x8,
10293 FLAG_IS_ALIGNED_HIGH = 0x10,
10294 FLAG_IS_NON_INTERLEAVED = 0x20
10296 _codec ("Raw LPCM audio");
10298 if (data && len >= 56) {
10299 depth = QT_UINT32 (data + 40);
10300 flags = QT_UINT32 (data + 44);
10301 width = QT_UINT32 (data + 48) * 8 / stream->n_channels;
10303 if ((flags & FLAG_IS_FLOAT) == 0) {
10308 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
10309 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
10310 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
10311 caps = gst_caps_new_simple ("audio/x-raw",
10312 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
10313 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
10314 "non-interleaved" : "interleaved", NULL);
10321 if (flags & FLAG_IS_BIG_ENDIAN)
10322 format = GST_AUDIO_FORMAT_F64BE;
10324 format = GST_AUDIO_FORMAT_F64LE;
10326 if (flags & FLAG_IS_BIG_ENDIAN)
10327 format = GST_AUDIO_FORMAT_F32BE;
10329 format = GST_AUDIO_FORMAT_F32LE;
10331 caps = gst_caps_new_simple ("audio/x-raw",
10332 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
10333 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
10334 "non-interleaved" : "interleaved", NULL);
10338 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
10342 char *s, fourstr[5];
10344 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
10345 s = g_strdup_printf ("audio/x-gst-fourcc-%s", g_strstrip (fourstr));
10346 caps = gst_caps_new_empty_simple (s);
10352 GstCaps *templ_caps =
10353 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
10354 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
10355 gst_caps_unref (caps);
10356 gst_caps_unref (templ_caps);
10357 caps = intersection;
10360 /* enable clipping for raw audio streams */
10361 s = gst_caps_get_structure (caps, 0);
10362 name = gst_structure_get_name (s);
10363 if (g_str_has_prefix (name, "audio/x-raw")) {
10364 stream->need_clip = TRUE;
10365 stream->max_buffer_size = 4096 * stream->bytes_per_frame;
10366 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
10372 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
10373 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
10377 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
10380 case GST_MAKE_FOURCC ('m', 'p', '4', 's'):
10381 _codec ("DVD subtitle");
10382 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
10384 case GST_MAKE_FOURCC ('t', 'e', 'x', 't'):
10385 _codec ("Quicktime timed text");
10387 case GST_MAKE_FOURCC ('t', 'x', '3', 'g'):
10388 _codec ("3GPP timed text");
10390 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
10392 /* actual text piece needs to be extracted */
10393 stream->need_process = TRUE;
10397 char *s, fourstr[5];
10399 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
10400 s = g_strdup_printf ("text/x-gst-fourcc-%s", g_strstrip (fourstr));
10401 caps = gst_caps_new_empty_simple (s);
10409 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
10410 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
10415 case GST_MAKE_FOURCC ('m', '1', 'v', ' '):
10416 _codec ("MPEG 1 video");
10417 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
10418 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);