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>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
24 * SECTION:element-qtdemux
28 * Demuxes a .mov file into raw or compressed audio and/or video streams.
31 * This element supports both push and pull-based scheduling, depending on the
32 * capabilities of the upstream elements.
34 * <title>Example launch line</title>
37 * gst-launch filesrc location=test.mov ! qtdemux name=demux demux.audio_00 ! decodebin ! audioconvert ! audioresample ! autoaudiosink demux.video_00 ! queue ! decodebin ! ffmpegcolorspace ! videoscale ! autovideosink
39 * Play (parse and decode) a .mov file and try to output it to
40 * an automatically detected soundcard and videosink. If the MOV file contains
41 * compressed audio or video data, this will only work if you have the
42 * right decoder elements/plugins installed.
46 * Last reviewed on 2006-12-29 (0.10.5)
53 #include "gst/gst-i18n-plugin.h"
55 #include <gst/tag/tag.h>
57 #include "qtdemux_types.h"
58 #include "qtdemux_dump.h"
59 #include "qtdemux_fourcc.h"
61 #include "qtpalette.h"
70 GST_DEBUG_CATEGORY (qtdemux_debug);
73 #define qtdemux_dump_mem(a,b) gst_util_dump_mem(a,b)
75 #define qtdemux_dump_mem(a,b) /* */
78 typedef struct _QtNode QtNode;
79 typedef struct _QtDemuxSegment QtDemuxSegment;
80 typedef struct _QtDemuxSample QtDemuxSample;
94 GstClockTimeDiff pts_offset; /* Add this value to timestamp to get the pts */
95 guint64 timestamp; /* In GstClockTime */
96 guint64 duration; /* in GstClockTime */
97 gboolean keyframe; /* TRUE when this packet is a keyframe */
101 * Quicktime has tracks and segments. A track is a continuous piece of
102 * multimedia content. The track is not always played from start to finish but
103 * instead, pieces of the track are 'cut out' and played in sequence. This is
104 * what the segments do.
106 * Inside the track we have keyframes (K) and delta frames. The track has its
107 * own timing, which starts from 0 and extends to end. The position in the track
108 * is called the media_time.
110 * The segments now describe the pieces that should be played from this track
111 * and are basically tupples of media_time/duration/rate entries. We can have
112 * multiple segments and they are all played after one another. An example:
114 * segment 1: media_time: 1 second, duration: 1 second, rate 1
115 * segment 2: media_time: 3 second, duration: 2 second, rate 2
117 * To correctly play back this track, one must play: 1 second of media starting
118 * from media_time 1 followed by 2 seconds of media starting from media_time 3
121 * Each of the segments will be played at a specific time, the first segment at
122 * time 0, the second one after the duration of the first one, etc.. Note that
123 * the time in resulting playback is not identical to the media_time of the
126 * Visually, assuming the track has 4 second of media_time:
129 * .-----------------------------------------------------------.
130 * track: | K.....K.........K........K.......K.......K...........K... |
131 * '-----------------------------------------------------------'
133 * .------------^ ^ .----------^ ^
134 * / .-------------' / .------------------'
136 * .--------------. .--------------.
137 * | segment 1 | | segment 2 |
138 * '--------------' '--------------'
140 * The challenge here is to cut out the right pieces of the track for each of
141 * the playback segments. This fortunatly can easily be done with the SEGMENT
142 * events of gstreamer.
144 * For playback of segment 1, we need to provide the decoder with the keyframe
145 * (a), in the above figure, but we must instruct it only to output the decoded
146 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
147 * position set to the time of the segment: 0.
149 * We then proceed to push data from keyframe (a) to frame (b). The decoder
150 * decodes but clips all before media_time 1.
152 * After finishing a segment, we push out a new SEGMENT event with the clipping
153 * boundaries of the new data.
155 * This is a good usecase for the GStreamer accumulated SEGMENT events.
158 struct _QtDemuxSegment
160 /* global time and duration, all gst time */
164 /* media time of trak, all gst time */
170 struct _QtDemuxStream
180 guint64 duration; /* in timescale */
185 QtDemuxSample *samples;
186 gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */
187 guint32 min_duration; /* duration in timescale of first sample, used for figuring out
188 the framerate, in timescale units */
190 /* if we use chunks or samples */
197 /* Numerator/denominator framerate */
200 guint16 bits_per_sample;
201 guint16 color_table_id;
206 guint samples_per_packet;
207 guint samples_per_frame;
208 guint bytes_per_packet;
209 guint bytes_per_sample;
210 guint bytes_per_frame;
213 /* when a discontinuity is pending */
216 /* list of buffers to push first */
219 /* if we need to clip this buffer. This is only needed for uncompressed
223 /* current position */
224 guint32 segment_index;
225 guint32 sample_index;
226 guint64 time_position; /* in gst time */
228 /* the Gst segment we are processing out, used for clipping */
231 /* last GstFlowReturn */
232 GstFlowReturn last_ret;
234 /* quicktime segments */
236 QtDemuxSegment *segments;
243 QTDEMUX_STATE_INITIAL, /* Initial state (haven't got the header yet) */
244 QTDEMUX_STATE_HEADER, /* Parsing the header */
245 QTDEMUX_STATE_MOVIE, /* Parsing/Playing the media data */
246 QTDEMUX_STATE_BUFFER_MDAT /* Buffering the mdat atom */
249 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
250 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
252 static const GstElementDetails gst_qtdemux_details =
253 GST_ELEMENT_DETAILS ("QuickTime demuxer",
255 "Demultiplex a QuickTime file into audio and video streams",
256 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
258 static GstStaticPadTemplate gst_qtdemux_sink_template =
259 GST_STATIC_PAD_TEMPLATE ("sink",
262 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
266 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
267 GST_STATIC_PAD_TEMPLATE ("video_%02d",
270 GST_STATIC_CAPS_ANY);
272 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
273 GST_STATIC_PAD_TEMPLATE ("audio_%02d",
276 GST_STATIC_CAPS_ANY);
278 static GstElementClass *parent_class = NULL;
280 static void gst_qtdemux_class_init (GstQTDemuxClass * klass);
281 static void gst_qtdemux_base_init (GstQTDemuxClass * klass);
282 static void gst_qtdemux_init (GstQTDemux * quicktime_demux);
283 static void gst_qtdemux_dispose (GObject * object);
285 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
286 GstStateChange transition);
287 static gboolean qtdemux_sink_activate (GstPad * sinkpad);
288 static gboolean qtdemux_sink_activate_pull (GstPad * sinkpad, gboolean active);
289 static gboolean qtdemux_sink_activate_push (GstPad * sinkpad, gboolean active);
291 static void gst_qtdemux_loop (GstPad * pad);
292 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf);
293 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstEvent * event);
295 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux, guint8 * buffer,
297 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
298 guint8 * buffer, int length);
299 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
301 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
302 QtDemuxStream * stream, GNode * esds, GstTagList * list);
303 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
304 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
305 gchar ** codec_name);
306 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
307 QtDemuxStream * stream, guint32 fourcc, const guint8 * data, int len,
308 gchar ** codec_name);
311 gst_qtdemux_get_type (void)
313 static GType qtdemux_type = 0;
316 static const GTypeInfo qtdemux_info = {
317 sizeof (GstQTDemuxClass),
318 (GBaseInitFunc) gst_qtdemux_base_init, NULL,
319 (GClassInitFunc) gst_qtdemux_class_init,
320 NULL, NULL, sizeof (GstQTDemux), 0,
321 (GInstanceInitFunc) gst_qtdemux_init,
325 g_type_register_static (GST_TYPE_ELEMENT, "GstQTDemux", &qtdemux_info,
332 gst_qtdemux_base_init (GstQTDemuxClass * klass)
334 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
336 gst_element_class_add_pad_template (element_class,
337 gst_static_pad_template_get (&gst_qtdemux_sink_template));
338 gst_element_class_add_pad_template (element_class,
339 gst_static_pad_template_get (&gst_qtdemux_videosrc_template));
340 gst_element_class_add_pad_template (element_class,
341 gst_static_pad_template_get (&gst_qtdemux_audiosrc_template));
342 gst_element_class_set_details (element_class, &gst_qtdemux_details);
344 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
348 gst_qtdemux_class_init (GstQTDemuxClass * klass)
350 GObjectClass *gobject_class;
351 GstElementClass *gstelement_class;
353 gobject_class = (GObjectClass *) klass;
354 gstelement_class = (GstElementClass *) klass;
356 parent_class = g_type_class_peek_parent (klass);
358 gobject_class->dispose = gst_qtdemux_dispose;
360 gstelement_class->change_state = gst_qtdemux_change_state;
364 gst_qtdemux_init (GstQTDemux * qtdemux)
367 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
368 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
369 gst_pad_set_activatepull_function (qtdemux->sinkpad,
370 qtdemux_sink_activate_pull);
371 gst_pad_set_activatepush_function (qtdemux->sinkpad,
372 qtdemux_sink_activate_push);
373 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
374 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
375 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
377 qtdemux->state = QTDEMUX_STATE_INITIAL;
378 /* FIXME, use segment last_stop for this */
379 qtdemux->last_ts = GST_CLOCK_TIME_NONE;
380 qtdemux->pullbased = FALSE;
381 qtdemux->neededbytes = 16;
383 qtdemux->adapter = gst_adapter_new ();
385 qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
386 qtdemux->mdatbuffer = NULL;
387 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
391 gst_qtdemux_dispose (GObject * object)
393 GstQTDemux *qtdemux = GST_QTDEMUX (object);
395 if (qtdemux->adapter) {
396 g_object_unref (G_OBJECT (qtdemux->adapter));
397 qtdemux->adapter = NULL;
400 G_OBJECT_CLASS (parent_class)->dispose (object);
405 gst_qtdemux_src_convert (GstPad * pad, GstFormat src_format, gint64 src_value,
406 GstFormat * dest_format, gint64 * dest_value)
409 QtDemuxStream *stream = gst_pad_get_element_private (pad);
411 if (stream->subtype == GST_MAKE_FOURCC ('v', 'i', 'd', 'e') &&
412 (src_format == GST_FORMAT_BYTES || *dest_format == GST_FORMAT_BYTES))
415 switch (src_format) {
416 case GST_FORMAT_TIME:
417 switch (*dest_format) {
418 case GST_FORMAT_BYTES:
419 *dest_value = src_value * 1; /* FIXME */
421 case GST_FORMAT_DEFAULT:
422 *dest_value = src_value * 1; /* FIXME */
429 case GST_FORMAT_BYTES:
430 switch (*dest_format) {
431 case GST_FORMAT_TIME:
432 *dest_value = src_value * 1; /* FIXME */
439 case GST_FORMAT_DEFAULT:
440 switch (*dest_format) {
441 case GST_FORMAT_TIME:
442 *dest_value = src_value * 1; /* FIXME */
457 static const GstQueryType *
458 gst_qtdemux_get_src_query_types (GstPad * pad)
460 static const GstQueryType src_types[] = {
471 gst_qtdemux_get_duration (GstQTDemux * qtdemux, gint64 * duration)
475 *duration = GST_CLOCK_TIME_NONE;
477 if (qtdemux->duration != 0) {
478 if (qtdemux->duration != G_MAXINT32 && qtdemux->timescale != 0) {
479 *duration = gst_util_uint64_scale (qtdemux->duration,
480 GST_SECOND, qtdemux->timescale);
487 gst_qtdemux_handle_src_query (GstPad * pad, GstQuery * query)
489 gboolean res = FALSE;
490 GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
492 switch (GST_QUERY_TYPE (query)) {
493 case GST_QUERY_POSITION:
494 if (GST_CLOCK_TIME_IS_VALID (qtdemux->segment.last_stop)) {
495 gst_query_set_position (query, GST_FORMAT_TIME,
496 qtdemux->segment.last_stop);
500 case GST_QUERY_DURATION:{
503 gst_query_parse_duration (query, &fmt, NULL);
504 if (fmt == GST_FORMAT_TIME) {
505 gint64 duration = -1;
507 gst_qtdemux_get_duration (qtdemux, &duration);
509 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
515 case GST_QUERY_SEEKING:{
518 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
519 if (fmt == GST_FORMAT_TIME) {
520 gint64 duration = -1;
522 gst_qtdemux_get_duration (qtdemux, &duration);
523 gst_query_set_seeking (query, GST_FORMAT_TIME, qtdemux->pullbased,
530 res = gst_pad_query_default (pad, query);
534 gst_object_unref (qtdemux);
539 /* push event on all source pads; takes ownership of the event */
541 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
545 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
546 GST_EVENT_TYPE_NAME (event));
548 for (n = 0; n < qtdemux->n_streams; n++) {
551 if ((pad = qtdemux->streams[n]->pad))
552 gst_pad_push_event (pad, gst_event_ref (event));
554 gst_event_unref (event);
557 /* push a pending newsegment event, if any from the streaming thread */
559 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
561 if (qtdemux->pending_newsegment) {
562 gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
563 qtdemux->pending_newsegment = NULL;
567 /* find the index of the sample that includes the data for @media_time
569 * Returns the index of the sample or n_samples when the sample was not
572 /* FIXME, binary search would be nice here */
574 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
579 if (str->n_samples == 0)
582 for (i = 0; i < str->n_samples; i++) {
583 if (str->samples[i].timestamp > media_time) {
584 /* first sample after media_time, we need the previous one */
585 return (i == 0 ? 0 : i - 1);
588 return str->n_samples - 1;
591 /* find the index of the keyframe needed to decode the sample at @index
594 * Returns the index of the keyframe.
597 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
600 guint32 new_index = index;
602 if (index >= str->n_samples) {
603 new_index = str->n_samples;
607 /* all keyframes, return index */
608 if (str->all_keyframe) {
613 /* else go back until we have a keyframe */
615 if (str->samples[new_index].keyframe)
625 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index before index %u "
626 "gave %u", index, new_index);
631 /* find the segment for @time_position for @stream
633 * Returns -1 if the segment cannot be found.
636 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
637 guint64 time_position)
642 GST_LOG_OBJECT (qtdemux, "finding segment for %" GST_TIME_FORMAT,
643 GST_TIME_ARGS (time_position));
645 /* find segment corresponding to time_position if we are looking
648 for (i = 0; i < stream->n_segments; i++) {
649 QtDemuxSegment *segment = &stream->segments[i];
651 GST_LOG_OBJECT (qtdemux,
652 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
653 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
655 /* For the last segment we include stop_time in the last segment */
656 if (i < stream->n_segments - 1) {
657 if (segment->time <= time_position && time_position < segment->stop_time) {
658 GST_LOG_OBJECT (qtdemux, "segment %d matches", i);
663 if (segment->time <= time_position && time_position <= segment->stop_time) {
664 GST_LOG_OBJECT (qtdemux, "segment %d matches", i);
673 /* move the stream @str to the sample position @index.
675 * Updates @str->sample_index and marks discontinuity if needed.
678 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
681 /* no change needed */
682 if (index == str->sample_index)
685 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
688 /* position changed, we have a discont */
689 str->sample_index = index;
690 /* Each time we move in the stream we store the position where we are
692 str->from_sample = index;
698 * We set all segment_indexes in the streams to unknown and
699 * adjust the time_position to the desired position. this is enough
700 * to trigger a segment switch in the streaming thread to start
701 * streaming from the desired position.
703 * Keyframe seeking is a little more complicated when dealing with
704 * segments. Ideally we want to move to the previous keyframe in
705 * the segment but there might not be a keyframe in the segment. In
706 * fact, none of the segments could contain a keyframe. We take a
707 * practical approach: seek to the previous keyframe in the segment,
708 * if there is none, seek to the beginning of the segment.
710 * Called with STREAM_LOCK
713 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment)
715 gint64 desired_offset;
718 desired_offset = segment->last_stop;
720 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
721 GST_TIME_ARGS (desired_offset));
723 if (segment->flags & GST_SEEK_FLAG_KEY_UNIT) {
726 min_offset = desired_offset;
728 /* for each stream, find the index of the sample in the segment
729 * and move back to the previous keyframe. */
730 for (n = 0; n < qtdemux->n_streams; n++) {
732 guint32 index, kindex;
739 str = qtdemux->streams[n];
741 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_offset);
742 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
744 /* segment not found, continue with normal flow */
748 /* get segment and time in the segment */
749 seg = &str->segments[seg_idx];
750 seg_time = desired_offset - seg->time;
752 /* get the media time in the segment */
753 media_start = seg->media_start + seg_time;
755 /* get the index of the sample with media time */
756 index = gst_qtdemux_find_index (qtdemux, str, media_start);
757 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u",
758 GST_TIME_ARGS (media_start), index);
760 /* find previous keyframe */
761 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index);
763 /* if the keyframe is at a different position, we need to update the
764 * requiested seek time */
765 if (index != kindex) {
768 /* get timestamp of keyframe */
769 media_time = str->samples[kindex].timestamp;
770 GST_DEBUG_OBJECT (qtdemux, "keyframe at %u with time %" GST_TIME_FORMAT,
771 kindex, GST_TIME_ARGS (media_time));
773 /* keyframes in the segment get a chance to change the
774 * desired_offset. keyframes out of the segment are
776 if (media_time >= seg->media_start) {
779 /* this keyframe is inside the segment, convert back to
781 seg_time = (media_time - seg->media_start) + seg->time;
782 if (seg_time < min_offset)
783 min_offset = seg_time;
787 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
788 GST_TIME_FORMAT, GST_TIME_ARGS (desired_offset));
789 desired_offset = min_offset;
792 /* and set all streams to the final position */
793 for (n = 0; n < qtdemux->n_streams; n++) {
794 QtDemuxStream *stream = qtdemux->streams[n];
796 stream->time_position = desired_offset;
797 stream->sample_index = -1;
798 stream->segment_index = -1;
799 stream->last_ret = GST_FLOW_OK;
801 segment->last_stop = desired_offset;
802 segment->time = desired_offset;
804 /* we stop at the end */
805 if (segment->stop == -1)
806 segment->stop = segment->duration;
811 /* do a seek in pull based mode */
813 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
818 GstSeekType cur_type, stop_type;
823 GstSegment seeksegment;
827 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
829 gst_event_parse_seek (event, &rate, &format, &flags,
830 &cur_type, &cur, &stop_type, &stop);
832 /* we have to have a format as the segment format. Try to convert
834 if (format != GST_FORMAT_TIME) {
837 fmt = GST_FORMAT_TIME;
839 if (cur_type != GST_SEEK_TYPE_NONE)
840 res = gst_pad_query_convert (pad, format, cur, &fmt, &cur);
841 if (res && stop_type != GST_SEEK_TYPE_NONE)
842 res = gst_pad_query_convert (pad, format, stop, &fmt, &stop);
849 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
853 flush = flags & GST_SEEK_FLAG_FLUSH;
855 GST_DEBUG_OBJECT (qtdemux, "seek format %d", format);
857 /* stop streaming, either by flushing or by pausing the task */
859 /* unlock upstream pull_range */
860 gst_pad_push_event (qtdemux->sinkpad, gst_event_new_flush_start ());
861 /* make sure out loop function exits */
862 gst_qtdemux_push_event (qtdemux, gst_event_new_flush_start ());
864 /* non flushing seek, pause the task */
865 gst_pad_pause_task (qtdemux->sinkpad);
868 /* wait for streaming to finish */
869 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
871 /* copy segment, we need this because we still need the old
872 * segment when we close the current segment. */
873 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
876 /* configure the segment with the seek variables */
877 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
878 gst_segment_set_seek (&seeksegment, rate, format, flags,
879 cur_type, cur, stop_type, stop, &update);
882 /* now do the seek, this actually never returns FALSE */
883 res = gst_qtdemux_perform_seek (qtdemux, &seeksegment);
885 /* prepare for streaming again */
887 gst_pad_push_event (qtdemux->sinkpad, gst_event_new_flush_stop ());
888 gst_qtdemux_push_event (qtdemux, gst_event_new_flush_stop ());
889 } else if (qtdemux->segment_running) {
890 /* we are running the current segment and doing a non-flushing seek,
891 * close the segment first based on the last_stop. */
892 GST_DEBUG_OBJECT (qtdemux, "closing running segment %" G_GINT64_FORMAT
893 " to %" G_GINT64_FORMAT, qtdemux->segment.start,
894 qtdemux->segment.last_stop);
896 if (qtdemux->segment.rate >= 0) {
897 /* FIXME, rate is the product of the global rate and the (quicktime)
899 qtdemux->pending_newsegment = gst_event_new_new_segment (TRUE,
900 qtdemux->segment.rate, qtdemux->segment.format,
901 qtdemux->segment.start, qtdemux->segment.last_stop,
902 qtdemux->segment.time);
903 } else { /* For Reverse Playback */
906 if ((stop = qtdemux->segment.stop) == -1)
907 stop = qtdemux->segment.duration;
908 /* for reverse playback, we played from stop to last_stop. */
909 qtdemux->pending_newsegment = gst_event_new_new_segment (TRUE,
910 qtdemux->segment.rate, qtdemux->segment.format,
911 qtdemux->segment.last_stop, stop, qtdemux->segment.last_stop);
915 /* commit the new segment */
916 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
918 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
919 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
920 gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
921 qtdemux->segment.format, qtdemux->segment.last_stop));
924 /* restart streaming, NEWSEGMENT will be sent from the streaming
926 qtdemux->segment_running = TRUE;
927 for (i = 0; i < qtdemux->n_streams; i++)
928 qtdemux->streams[i]->last_ret = GST_FLOW_OK;
930 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
933 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
940 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
946 gst_qtdemux_handle_src_event (GstPad * pad, GstEvent * event)
949 GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
951 switch (GST_EVENT_TYPE (event)) {
953 if (qtdemux->pullbased) {
954 res = gst_qtdemux_do_seek (qtdemux, pad, event);
956 GST_DEBUG_OBJECT (qtdemux, "cannot seek in streaming mode");
959 gst_event_unref (event);
962 case GST_EVENT_NAVIGATION:
964 gst_event_unref (event);
967 res = gst_pad_event_default (pad, event);
971 gst_object_unref (qtdemux);
977 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstEvent * event)
979 GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad));
982 switch (GST_EVENT_TYPE (event)) {
983 case GST_EVENT_NEWSEGMENT:
984 /* We need to convert it to a GST_FORMAT_TIME new segment */
985 gst_event_unref (event);
989 res = gst_pad_event_default (demux->sinkpad, event);
996 static GstStateChangeReturn
997 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
999 GstQTDemux *qtdemux = GST_QTDEMUX (element);
1000 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
1002 switch (transition) {
1003 case GST_STATE_CHANGE_PAUSED_TO_READY:
1009 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1011 switch (transition) {
1012 case GST_STATE_CHANGE_PAUSED_TO_READY:{
1015 qtdemux->state = QTDEMUX_STATE_INITIAL;
1016 qtdemux->last_ts = GST_CLOCK_TIME_NONE;
1017 qtdemux->neededbytes = 16;
1018 qtdemux->todrop = 0;
1019 qtdemux->pullbased = FALSE;
1020 qtdemux->offset = 0;
1021 qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
1022 if (qtdemux->mdatbuffer)
1023 gst_buffer_unref (qtdemux->mdatbuffer);
1024 qtdemux->mdatbuffer = NULL;
1025 gst_adapter_clear (qtdemux->adapter);
1026 for (n = 0; n < qtdemux->n_streams; n++) {
1027 QtDemuxStream *stream = qtdemux->streams[n];
1029 while (stream->buffers) {
1030 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
1032 g_slist_delete_link (stream->buffers, stream->buffers);
1035 gst_element_remove_pad (element, stream->pad);
1036 if (stream->samples)
1037 g_free (stream->samples);
1039 gst_caps_unref (stream->caps);
1040 if (stream->segments)
1041 g_free (stream->segments);
1044 qtdemux->major_brand = 0;
1045 qtdemux->n_streams = 0;
1046 qtdemux->n_video_streams = 0;
1047 qtdemux->n_audio_streams = 0;
1048 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
1059 extract_initial_length_and_fourcc (guint8 * data, guint64 * plength,
1065 length = QT_UINT32 (data);
1066 GST_DEBUG ("length %08" G_GINT64_MODIFIER "x", length);
1067 fourcc = QT_FOURCC (data + 4);
1068 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
1071 length = G_MAXUINT32;
1072 } else if (length == 1) {
1073 /* this means we have an extended size, which is the 64 bit value of
1074 * the next 8 bytes */
1075 length = QT_UINT64 (data + 8);
1076 GST_DEBUG ("length %08llx", length);
1085 static GstFlowReturn
1086 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
1090 GstBuffer *buf = NULL;
1091 GstFlowReturn ret = GST_FLOW_OK;
1092 guint64 cur_offset = qtdemux->offset;
1094 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
1095 if (ret != GST_FLOW_OK)
1097 extract_initial_length_and_fourcc (GST_BUFFER_DATA (buf), &length, &fourcc);
1098 gst_buffer_unref (buf);
1101 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
1102 (_("This file is invalid and cannot be played.")),
1103 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
1104 GST_FOURCC_ARGS (fourcc)));
1105 ret = GST_FLOW_ERROR;
1116 GST_LOG_OBJECT (qtdemux,
1117 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
1118 GST_FOURCC_ARGS (fourcc), cur_offset);
1119 cur_offset += length;
1120 qtdemux->offset += length;
1127 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
1128 if (ret != GST_FLOW_OK)
1130 if (length != GST_BUFFER_SIZE (moov)) {
1131 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
1132 (_("This file is incomplete and cannot be played.")),
1133 ("We got less than expected (received %u, wanted %u)",
1134 GST_BUFFER_SIZE (moov), (guint) length));
1135 ret = GST_FLOW_ERROR;
1138 cur_offset += length;
1139 qtdemux->offset += length;
1141 qtdemux_parse_moov (qtdemux, GST_BUFFER_DATA (moov), length);
1142 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
1144 qtdemux_parse_tree (qtdemux);
1145 g_node_destroy (qtdemux->moov_node);
1146 gst_buffer_unref (moov);
1147 qtdemux->moov_node = NULL;
1148 qtdemux->state = QTDEMUX_STATE_MOVIE;
1149 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
1157 /* extract major brand; might come in handy for ISO vs QT issues */
1158 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &ftyp);
1159 if (ret != GST_FLOW_OK)
1161 cur_offset += length;
1162 qtdemux->offset += length;
1163 /* only consider at least a sufficiently complete ftyp atom */
1165 qtdemux->major_brand = QT_FOURCC (GST_BUFFER_DATA (ftyp) + 8);
1166 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
1167 GST_FOURCC_ARGS (qtdemux->major_brand));
1169 gst_buffer_unref (ftyp);
1174 GST_LOG_OBJECT (qtdemux,
1175 "unknown %08x '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT, fourcc,
1176 GST_FOURCC_ARGS (fourcc), cur_offset);
1177 cur_offset += length;
1178 qtdemux->offset += length;
1187 /* Seeks to the previous keyframe of the indexed stream and
1188 * aligns other streams with respect to the keyframe timestamp
1189 * of indexed stream. Only called in case of Reverse Playback
1191 static GstFlowReturn
1192 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
1195 guint32 seg_idx = 0, k_index = 0;
1196 guint64 k_pos = 0, last_stop = 0;
1197 QtDemuxSegment *seg = NULL;
1198 QtDemuxStream *ref_str = NULL;
1200 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
1201 * and finally align all the other streams on that timestamp with their
1202 * respective keyframes */
1203 for (n = 0; n < qtdemux->n_streams; n++) {
1204 QtDemuxStream *str = qtdemux->streams[n];
1206 seg_idx = gst_qtdemux_find_segment (qtdemux, str,
1207 qtdemux->segment.last_stop);
1209 /* segment not found, continue with normal flow */
1213 /* No candidate yet, take that one */
1219 /* So that stream has a segment, we prefer video streams */
1220 if (str->subtype == FOURCC_vide) {
1226 if (G_UNLIKELY (!ref_str)) {
1227 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
1231 if (G_UNLIKELY (!ref_str->from_sample)) {
1232 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
1236 /* So that stream has been playing from from_sample to to_sample. We will
1237 * get the timestamp of the previous sample and search for a keyframe before
1238 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
1239 if (ref_str->subtype == FOURCC_vide) {
1240 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
1241 ref_str->from_sample - 1);
1243 k_index = ref_str->from_sample - 10;
1246 /* get current segment for that stream */
1247 seg = &ref_str->segments[ref_str->segment_index];
1248 /* Crawl back through segments to find the one containing this I frame */
1249 while (ref_str->samples[k_index].timestamp < seg->media_start) {
1250 GST_DEBUG_OBJECT (qtdemux, "keyframe position is out of segment %u",
1251 ref_str->segment_index);
1252 if (G_UNLIKELY (!ref_str->segment_index)) {
1253 /* Reached first segment, let's consider it's EOS */
1256 ref_str->segment_index--;
1257 seg = &ref_str->segments[ref_str->segment_index];
1259 /* Calculate time position of the keyframe and where we should stop */
1260 k_pos = (ref_str->samples[k_index].timestamp - seg->media_start) + seg->time;
1261 last_stop = ref_str->samples[ref_str->from_sample].timestamp;
1262 last_stop = (last_stop - seg->media_start) + seg->time;
1264 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
1265 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
1266 k_index, GST_TIME_ARGS (k_pos));
1268 /* Set last_stop with the keyframe timestamp we pushed of that stream */
1269 gst_segment_set_last_stop (&qtdemux->segment, GST_FORMAT_TIME, last_stop);
1270 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
1271 GST_TIME_ARGS (last_stop));
1273 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
1274 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
1278 /* Align them all on this */
1279 for (n = 0; n < qtdemux->n_streams; n++) {
1281 guint64 media_start = 0, seg_time = 0;
1282 QtDemuxStream *str = qtdemux->streams[n];
1284 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
1285 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1287 /* segment not found, continue with normal flow */
1291 /* get segment and time in the segment */
1292 seg = &str->segments[seg_idx];
1293 seg_time = k_pos - seg->time;
1295 /* get the media time in the segment */
1296 media_start = seg->media_start + seg_time;
1298 /* get the index of the sample with media time */
1299 index = gst_qtdemux_find_index (qtdemux, str, media_start);
1300 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u",
1301 GST_TIME_ARGS (media_start), index);
1303 /* find previous keyframe */
1304 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index);
1306 /* Remember until where we want to go */
1307 str->to_sample = str->from_sample - 1;
1308 /* Define our time position */
1309 str->time_position =
1310 (str->samples[k_index].timestamp - seg->media_start) + seg->time;
1311 /* Now seek back in time */
1312 gst_qtdemux_move_stream (qtdemux, str, k_index);
1313 GST_DEBUG_OBJECT (qtdemux, "keyframe at %u, time position %"
1314 GST_TIME_FORMAT " playing from sample %u to %u", k_index,
1315 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
1321 return GST_FLOW_UNEXPECTED;
1324 /* activate the given segment number @seg_idx of @stream at time @offset.
1325 * @offset is an absolute global position over all the segments.
1327 * This will push out a NEWSEGMENT event with the right values and
1328 * position the stream index to the first decodable sample before
1332 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1333 guint32 seg_idx, guint64 offset)
1336 QtDemuxSegment *segment;
1337 guint32 index, kf_index;
1339 guint64 start, stop, time;
1342 GST_LOG_OBJECT (qtdemux, "activate segment %d, offset %" G_GUINT64_FORMAT,
1345 /* update the current segment */
1346 stream->segment_index = seg_idx;
1348 /* get the segment */
1349 segment = &stream->segments[seg_idx];
1351 if (offset < segment->time) {
1352 GST_WARNING_OBJECT (qtdemux, "offset < segment->time %" G_GUINT64_FORMAT,
1357 /* get time in this segment */
1358 seg_time = offset - segment->time;
1360 GST_LOG_OBJECT (qtdemux, "seg_time %" GST_TIME_FORMAT,
1361 GST_TIME_ARGS (seg_time));
1363 if (seg_time > segment->duration) {
1364 GST_LOG_OBJECT (qtdemux, "seg_time > segment->duration %" GST_TIME_FORMAT,
1365 GST_TIME_ARGS (segment->duration));
1369 /* qtdemux->segment.stop is in outside-time-realm, whereas
1370 * segment->media_stop is in track-time-realm.
1372 * In order to compare the two, we need to bring segment.stop
1373 * into the track-time-realm */
1375 if (qtdemux->segment.stop == -1)
1376 stop = segment->media_stop;
1379 MIN (segment->media_stop,
1380 qtdemux->segment.stop - segment->time + segment->media_start);
1382 if (qtdemux->segment.rate >= 0) {
1383 start = MIN (segment->media_start + seg_time, stop);
1386 start = segment->media_start;
1387 stop = MIN (segment->media_start + seg_time, stop);
1388 time = segment->time;
1391 GST_DEBUG_OBJECT (qtdemux, "newsegment %d from %" GST_TIME_FORMAT
1392 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
1393 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
1395 /* combine global rate with that of the segment */
1396 rate = segment->rate * qtdemux->segment.rate;
1398 /* update the segment values used for clipping */
1399 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1400 gst_segment_set_newsegment (&stream->segment, FALSE, rate, GST_FORMAT_TIME,
1403 /* now prepare and send the segment */
1405 event = gst_event_new_new_segment (FALSE, rate, GST_FORMAT_TIME,
1407 gst_pad_push_event (stream->pad, event);
1408 /* assume we can send more data now */
1409 stream->last_ret = GST_FLOW_OK;
1412 /* and move to the keyframe before the indicated media time of the
1414 if (qtdemux->segment.rate >= 0) {
1415 index = gst_qtdemux_find_index (qtdemux, stream, start);
1416 stream->to_sample = stream->n_samples;
1417 GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
1418 ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
1419 GST_TIME_ARGS (stream->samples[index].timestamp));
1421 index = gst_qtdemux_find_index (qtdemux, stream, stop);
1422 stream->to_sample = index;
1423 GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
1424 ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
1425 GST_TIME_ARGS (stream->samples[index].timestamp));
1428 /* we're at the right spot */
1429 if (index == stream->sample_index) {
1430 GST_DEBUG_OBJECT (qtdemux, "we are at the right index");
1434 /* find keyframe of the target index */
1435 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index);
1437 /* if we move forwards, we don't have to go back to the previous
1438 * keyframe since we already sent that. We can also just jump to
1439 * the keyframe right before the target index if there is one. */
1440 if (index > stream->sample_index) {
1441 /* moving forwards check if we move past a keyframe */
1442 if (kf_index > stream->sample_index) {
1443 GST_DEBUG_OBJECT (qtdemux, "moving forwards to keyframe at %u (pts %"
1444 GST_TIME_FORMAT, kf_index,
1445 GST_TIME_ARGS (stream->samples[kf_index].timestamp));
1446 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
1448 GST_DEBUG_OBJECT (qtdemux, "moving forwards, keyframe at %u (pts %"
1449 GST_TIME_FORMAT " already sent", kf_index,
1450 GST_TIME_ARGS (stream->samples[kf_index].timestamp));
1453 GST_DEBUG_OBJECT (qtdemux, "moving backwards to keyframe at %u (pts %"
1454 GST_TIME_FORMAT, kf_index,
1455 GST_TIME_ARGS (stream->samples[kf_index].timestamp));
1456 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
1462 /* prepare to get the current sample of @stream, getting essential values.
1464 * This function will also prepare and send the segment when needed.
1466 * Return FALSE if the stream is EOS.
1469 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
1470 QtDemuxStream * stream, guint64 * offset, guint * size, guint64 * timestamp,
1471 guint64 * duration, gboolean * keyframe)
1473 QtDemuxSample *sample;
1474 guint64 time_position;
1477 g_return_val_if_fail (stream != NULL, FALSE);
1479 time_position = stream->time_position;
1480 if (time_position == -1)
1483 seg_idx = stream->segment_index;
1484 if (seg_idx == -1) {
1485 /* find segment corresponding to time_position if we are looking
1487 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
1489 /* nothing found, we're really eos */
1494 /* different segment, activate it, sample_index will be set. */
1495 if (stream->segment_index != seg_idx)
1496 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
1498 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
1499 stream->sample_index, stream->n_samples);
1501 /* send out pending buffers */
1502 while (stream->buffers) {
1503 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
1505 if (stream->discont) {
1506 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
1507 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
1508 stream->discont = FALSE;
1510 gst_buffer_set_caps (buffer, stream->caps);
1512 gst_pad_push (stream->pad, buffer);
1514 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
1517 if (stream->sample_index >= stream->n_samples)
1520 /* now get the info for the sample we're at */
1521 sample = &stream->samples[stream->sample_index];
1523 *timestamp = sample->timestamp + sample->pts_offset;
1524 *offset = sample->offset;
1525 *size = sample->size;
1526 *duration = sample->duration;
1527 *keyframe = stream->all_keyframe || sample->keyframe;
1530 if (stream->padding) {
1531 *offset += stream->padding;
1532 *size -= stream->padding;
1540 stream->time_position = -1;
1545 /* move to the next sample in @stream.
1547 * Moves to the next segment when needed.
1550 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
1552 QtDemuxSample *sample;
1553 QtDemuxSegment *segment;
1555 if (stream->sample_index >= stream->to_sample) {
1556 /* Mark the stream as EOS */
1557 GST_DEBUG_OBJECT (qtdemux, "reached max allowed sample %u, mark EOS",
1559 stream->time_position = -1;
1563 /* move to next sample */
1564 stream->sample_index++;
1566 /* get current segment */
1567 segment = &stream->segments[stream->segment_index];
1569 /* reached the last sample, we need the next segment */
1570 if (stream->sample_index >= stream->n_samples)
1573 /* get next sample */
1574 sample = &stream->samples[stream->sample_index];
1576 /* see if we are past the segment */
1577 if (sample->timestamp >= segment->media_stop)
1580 if (sample->timestamp >= segment->media_start) {
1581 /* inside the segment, update time_position, looks very familiar to
1582 * GStreamer segments, doesn't it? */
1583 stream->time_position =
1584 (sample->timestamp - segment->media_start) + segment->time;
1586 /* not yet in segment, time does not yet increment. This means
1587 * that we are still prerolling keyframes to the decoder so it can
1588 * decode the first sample of the segment. */
1589 stream->time_position = segment->time;
1593 /* move to the next segment */
1596 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
1598 if (stream->segment_index == stream->n_segments - 1) {
1599 /* are we at the end of the last segment, we're EOS */
1600 stream->time_position = -1;
1602 /* else we're only at the end of the current segment */
1603 stream->time_position = segment->stop_time;
1605 /* make sure we select a new segment */
1606 stream->segment_index = -1;
1610 /* UNEXPECTED and NOT_LINKED need to be combined. This means that we return:
1612 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
1613 * GST_FLOW_UNEXPECTED: when all pads UNEXPECTED or NOT_LINKED.
1615 static GstFlowReturn
1616 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
1620 gboolean unexpected = FALSE, not_linked = TRUE;
1622 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
1624 /* store the value */
1625 stream->last_ret = ret;
1627 for (i = 0; i < demux->n_streams; i++) {
1628 QtDemuxStream *ostream = demux->streams[i];
1630 ret = ostream->last_ret;
1632 /* no unexpected or unlinked, return */
1633 if (ret != GST_FLOW_UNEXPECTED && ret != GST_FLOW_NOT_LINKED)
1636 /* we check to see if we have at least 1 unexpected or all unlinked */
1637 unexpected |= (ret == GST_FLOW_UNEXPECTED);
1638 not_linked &= (ret == GST_FLOW_NOT_LINKED);
1640 /* when we get here, we all have unlinked or unexpected */
1642 ret = GST_FLOW_NOT_LINKED;
1643 else if (unexpected)
1644 ret = GST_FLOW_UNEXPECTED;
1646 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
1650 /* the input buffer metadata must be writable. Returns NULL when the buffer is
1651 * completely cliped */
1653 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
1656 gint64 start, stop, cstart, cstop, diff;
1657 GstClockTime timestamp = GST_CLOCK_TIME_NONE, duration = GST_CLOCK_TIME_NONE;
1660 gint num_rate, denom_rate;
1664 data = GST_BUFFER_DATA (buf);
1665 size = GST_BUFFER_SIZE (buf);
1667 /* depending on the type, setup the clip parameters */
1668 if (stream->subtype == FOURCC_soun) {
1669 frame_size = stream->bytes_per_frame;
1670 num_rate = GST_SECOND;
1671 denom_rate = (gint) stream->rate;
1673 } else if (stream->subtype == FOURCC_vide) {
1675 num_rate = stream->fps_n;
1676 denom_rate = stream->fps_d;
1681 /* we can only clip if we have a valid timestamp */
1682 timestamp = GST_BUFFER_TIMESTAMP (buf);
1683 if (!GST_CLOCK_TIME_IS_VALID (timestamp))
1686 if (GST_BUFFER_DURATION_IS_VALID (buf)) {
1687 duration = GST_BUFFER_DURATION (buf);
1690 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
1694 stop = start + duration;
1696 if (!gst_segment_clip (&stream->segment, GST_FORMAT_TIME,
1697 start, stop, &cstart, &cstop))
1700 /* see if some clipping happened */
1701 diff = cstart - start;
1707 /* bring clipped time to samples and to bytes */
1708 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
1711 GST_DEBUG_OBJECT (qtdemux, "clipping start to %" GST_TIME_FORMAT " %"
1712 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
1718 diff = stop - cstop;
1723 /* bring clipped time to samples and then to bytes */
1724 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
1727 GST_DEBUG_OBJECT (qtdemux, "clipping stop to %" GST_TIME_FORMAT " %"
1728 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstop), diff);
1734 GST_BUFFER_TIMESTAMP (buf) = timestamp;
1735 GST_BUFFER_DURATION (buf) = duration;
1736 GST_BUFFER_SIZE (buf) = size;
1737 GST_BUFFER_DATA (buf) = data;
1741 /* dropped buffer */
1744 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
1749 GST_DEBUG_OBJECT (qtdemux, "no timestamp on buffer");
1754 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
1755 gst_buffer_unref (buf);
1760 static GstFlowReturn
1761 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
1763 GstFlowReturn ret = GST_FLOW_OK;
1764 GstBuffer *buf = NULL;
1765 QtDemuxStream *stream;
1775 gst_qtdemux_push_pending_newsegment (qtdemux);
1777 /* Figure out the next stream sample to output, min_time is expressed in
1778 * global time and runs over the edit list segments. */
1779 min_time = G_MAXUINT64;
1781 for (i = 0; i < qtdemux->n_streams; i++) {
1784 stream = qtdemux->streams[i];
1785 position = stream->time_position;
1787 /* position of -1 is EOS */
1788 if (position != -1 && position < min_time) {
1789 min_time = position;
1795 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
1799 /* check for segment end */
1800 if (qtdemux->segment.stop != -1 && qtdemux->segment.stop < min_time) {
1801 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
1805 stream = qtdemux->streams[index];
1807 /* fetch info for the current sample of this stream */
1808 if (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &offset, &size,
1809 ×tamp, &duration, &keyframe))
1812 GST_LOG_OBJECT (qtdemux,
1813 "pushing from stream %d, offset %" G_GUINT64_FORMAT
1814 ", size %d, timestamp=%" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT,
1815 index, offset, size, GST_TIME_ARGS (timestamp), GST_TIME_ARGS (duration));
1817 /* hmm, empty sample, skip and move to next sample */
1818 if (G_UNLIKELY (size <= 0))
1821 /* last pushed sample was out of boundary, goto next sample */
1822 if (stream->last_ret == GST_FLOW_UNEXPECTED)
1825 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
1828 ret = gst_pad_pull_range (qtdemux->sinkpad, offset, size, &buf);
1829 if (ret != GST_FLOW_OK)
1832 if (stream->fourcc == FOURCC_rtsp) {
1836 url = g_strndup ((gchar *) GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
1838 /* we have RTSP redirect now */
1839 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
1840 gst_structure_new ("redirect",
1841 "new-location", G_TYPE_STRING, url, NULL));
1844 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
1847 qtdemux->last_ts = min_time;
1848 if (qtdemux->segment.rate >= 0) {
1849 gst_segment_set_last_stop (&qtdemux->segment, GST_FORMAT_TIME, min_time);
1852 /* we're going to modify the metadata */
1853 buf = gst_buffer_make_metadata_writable (buf);
1855 GST_BUFFER_TIMESTAMP (buf) = timestamp;
1856 GST_BUFFER_DURATION (buf) = duration;
1857 GST_BUFFER_OFFSET (buf) = -1;
1858 GST_BUFFER_OFFSET_END (buf) = -1;
1860 if (stream->need_clip)
1861 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
1866 if (stream->discont) {
1867 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
1868 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
1869 stream->discont = FALSE;
1873 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
1875 gst_buffer_set_caps (buf, stream->caps);
1877 GST_LOG_OBJECT (qtdemux,
1878 "Pushing buffer with time %" GST_TIME_FORMAT ", duration %"
1879 GST_TIME_FORMAT " on pad %s",
1880 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
1881 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_PAD_NAME (stream->pad));
1883 ret = gst_pad_push (stream->pad, buf);
1885 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
1886 gst_buffer_unref (buf);
1891 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
1892 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
1893 * we have no more data for the pad to push */
1894 if (ret == GST_FLOW_UNEXPECTED)
1898 gst_qtdemux_advance_sample (qtdemux, stream);
1906 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
1907 ret = GST_FLOW_UNEXPECTED;
1913 gst_qtdemux_loop (GstPad * pad)
1915 GstQTDemux *qtdemux;
1919 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
1921 cur_offset = qtdemux->offset;
1922 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %d",
1923 cur_offset, qtdemux->state);
1925 switch (qtdemux->state) {
1926 case QTDEMUX_STATE_INITIAL:
1927 case QTDEMUX_STATE_HEADER:
1928 ret = gst_qtdemux_loop_state_header (qtdemux);
1930 case QTDEMUX_STATE_MOVIE:
1931 ret = gst_qtdemux_loop_state_movie (qtdemux);
1932 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_UNEXPECTED) {
1933 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
1941 /* if something went wrong, pause */
1942 if (ret != GST_FLOW_OK)
1946 gst_object_unref (qtdemux);
1952 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
1953 (NULL), ("streaming stopped, invalid state"));
1954 qtdemux->segment_running = FALSE;
1955 gst_pad_pause_task (pad);
1956 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
1961 const gchar *reason = gst_flow_get_name (ret);
1963 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
1965 qtdemux->segment_running = FALSE;
1966 gst_pad_pause_task (pad);
1968 /* fatal errors need special actions */
1969 if (GST_FLOW_IS_FATAL (ret) || ret == GST_FLOW_NOT_LINKED) {
1971 if (ret == GST_FLOW_UNEXPECTED) {
1972 if (qtdemux->n_streams == 0) {
1973 /* we have no streams, post an error */
1974 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
1975 (_("This file contains no playable streams.")),
1976 ("no known streams found"));
1978 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1981 /* FIXME: I am not sure this is the right fix. If the sinks are
1982 * supposed to detect the segment is complete and accumulate
1983 * automatically, it does not seem to work here. Need more work */
1984 qtdemux->segment_running = TRUE;
1986 if ((stop = qtdemux->segment.stop) == -1)
1987 stop = qtdemux->segment.duration;
1989 if (qtdemux->segment.rate >= 0) {
1990 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
1991 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
1992 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
1993 GST_FORMAT_TIME, stop));
1995 /* For Reverse Playback */
1996 GST_LOG_OBJECT (qtdemux,
1997 "Sending segment done, at start of segment");
1998 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
1999 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
2000 GST_FORMAT_TIME, qtdemux->segment.start));
2003 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
2004 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
2007 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
2008 (NULL), ("streaming stopped, reason %s", reason));
2009 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
2019 * Returns the size of the first entry at the current offset.
2020 * If -1, there are none (which means EOS or empty file).
2023 next_entry_size (GstQTDemux * demux)
2025 QtDemuxStream *stream;
2028 guint64 smalloffs = (guint64) - 1;
2030 GST_LOG_OBJECT (demux, "Finding entry at offset %lld", demux->offset);
2032 for (i = 0; i < demux->n_streams; i++) {
2033 stream = demux->streams[i];
2035 if (stream->sample_index == -1)
2036 stream->sample_index = 0;
2038 GST_LOG_OBJECT (demux,
2039 "Checking Stream %d (sample_index:%d / offset:%lld / size:%d / chunk:%d)",
2040 i, stream->sample_index, stream->samples[stream->sample_index].offset,
2041 stream->samples[stream->sample_index].size,
2042 stream->samples[stream->sample_index].chunk);
2044 if (((smalloffs == -1)
2045 || (stream->samples[stream->sample_index].offset < smalloffs))
2046 && (stream->samples[stream->sample_index].size)) {
2048 smalloffs = stream->samples[stream->sample_index].offset;
2052 GST_LOG_OBJECT (demux, "stream %d offset %lld demux->offset :%lld",
2053 smallidx, smalloffs, demux->offset);
2057 stream = demux->streams[smallidx];
2059 if (stream->samples[stream->sample_index].offset >= demux->offset) {
2061 stream->samples[stream->sample_index].offset - demux->offset;
2062 return stream->samples[stream->sample_index].size + demux->todrop;
2065 GST_DEBUG_OBJECT (demux, "There wasn't any entry at offset %lld",
2071 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
2073 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
2075 gst_element_post_message (GST_ELEMENT_CAST (demux),
2076 gst_message_new_element (GST_OBJECT_CAST (demux),
2077 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
2080 /* FIXME, unverified after edit list updates */
2081 static GstFlowReturn
2082 gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf)
2085 GstFlowReturn ret = GST_FLOW_OK;
2087 demux = GST_QTDEMUX (gst_pad_get_parent (sinkpad));
2089 gst_adapter_push (demux->adapter, inbuf);
2091 GST_DEBUG_OBJECT (demux, "pushing in inbuf %p, neededbytes:%u, available:%u",
2092 inbuf, demux->neededbytes, gst_adapter_available (demux->adapter));
2094 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
2095 (ret == GST_FLOW_OK)) {
2097 GST_DEBUG_OBJECT (demux,
2098 "state:%d , demux->neededbytes:%d, demux->offset:%lld", demux->state,
2099 demux->neededbytes, demux->offset);
2101 switch (demux->state) {
2102 case QTDEMUX_STATE_INITIAL:{
2107 data = gst_adapter_peek (demux->adapter, demux->neededbytes);
2109 /* get fourcc/length, set neededbytes */
2110 extract_initial_length_and_fourcc ((guint8 *) data, &size, &fourcc);
2111 GST_DEBUG_OBJECT (demux,
2112 "Peeking found [%" GST_FOURCC_FORMAT "] size: %u",
2113 GST_FOURCC_ARGS (fourcc), (guint) size);
2115 GST_ELEMENT_ERROR (demux, STREAM, DECODE,
2116 (_("This file is invalid and cannot be played.")),
2117 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
2118 GST_FOURCC_ARGS (fourcc)));
2119 ret = GST_FLOW_ERROR;
2122 if (fourcc == FOURCC_mdat) {
2123 if (demux->n_streams > 0) {
2124 demux->state = QTDEMUX_STATE_MOVIE;
2125 demux->neededbytes = next_entry_size (demux);
2127 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
2128 demux->neededbytes = size;
2129 demux->mdatoffset = demux->offset;
2132 demux->neededbytes = size;
2133 demux->state = QTDEMUX_STATE_HEADER;
2137 case QTDEMUX_STATE_HEADER:{
2141 GST_DEBUG_OBJECT (demux, "In header");
2143 data = gst_adapter_take (demux->adapter, demux->neededbytes);
2145 /* parse the header */
2146 extract_initial_length_and_fourcc (data, NULL, &fourcc);
2147 if (fourcc == FOURCC_moov) {
2148 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
2150 qtdemux_parse_moov (demux, data, demux->neededbytes);
2151 qtdemux_node_dump (demux, demux->moov_node);
2152 qtdemux_parse_tree (demux);
2154 g_node_destroy (demux->moov_node);
2156 demux->moov_node = NULL;
2158 GST_WARNING_OBJECT (demux,
2159 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
2160 GST_FOURCC_ARGS (fourcc));
2161 /* Let's jump that one and go back to initial state */
2164 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
2165 if (demux->mdatbuffer && demux->n_streams) {
2166 /* the mdat was before the header */
2167 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
2168 demux->n_streams, demux->mdatbuffer);
2169 gst_adapter_clear (demux->adapter);
2170 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
2171 GST_FOURCC_ARGS (QT_UINT32 (demux->mdatbuffer)));
2172 gst_adapter_push (demux->adapter, demux->mdatbuffer);
2173 demux->mdatbuffer = NULL;
2174 demux->offset = demux->mdatoffset;
2175 demux->neededbytes = next_entry_size (demux);
2176 demux->state = QTDEMUX_STATE_MOVIE;
2178 GST_DEBUG_OBJECT (demux, "Carrying on normally");
2179 demux->offset += demux->neededbytes;
2180 demux->neededbytes = 16;
2181 demux->state = QTDEMUX_STATE_INITIAL;
2186 case QTDEMUX_STATE_BUFFER_MDAT:{
2187 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %lld",
2189 if (demux->mdatbuffer)
2190 gst_buffer_unref (demux->mdatbuffer);
2191 demux->mdatbuffer = gst_buffer_new ();
2192 gst_buffer_set_data (demux->mdatbuffer,
2193 gst_adapter_take (demux->adapter, demux->neededbytes),
2194 demux->neededbytes);
2195 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
2196 GST_FOURCC_ARGS (QT_UINT32 (demux->mdatbuffer)));
2197 demux->offset += demux->neededbytes;
2198 demux->neededbytes = 16;
2199 demux->state = QTDEMUX_STATE_INITIAL;
2200 gst_qtdemux_post_progress (demux, 1, 1);
2204 case QTDEMUX_STATE_MOVIE:{
2207 QtDemuxStream *stream = NULL;
2210 GST_DEBUG_OBJECT (demux, "BEGIN // in MOVIE for offset %lld",
2213 if (demux->todrop) {
2214 gst_adapter_flush (demux->adapter, demux->todrop);
2215 demux->neededbytes -= demux->todrop;
2216 demux->offset += demux->todrop;
2219 /* Figure out which stream this is packet belongs to */
2220 for (i = 0; i < demux->n_streams; i++) {
2221 stream = demux->streams[i];
2222 GST_LOG_OBJECT (demux,
2223 "Checking stream %d (sample_index:%d / offset:%lld / size:%d / chunk:%d)",
2224 i, stream->sample_index,
2225 stream->samples[stream->sample_index].offset,
2226 stream->samples[stream->sample_index].size,
2227 stream->samples[stream->sample_index].chunk);
2229 if (stream->samples[stream->sample_index].offset == demux->offset)
2234 goto unknown_stream;
2237 /* FIXME : this should be handled in sink_event */
2238 if (demux->last_ts == GST_CLOCK_TIME_NONE) {
2239 gst_qtdemux_push_event (demux,
2240 gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME,
2241 0, GST_CLOCK_TIME_NONE, 0));
2245 data = gst_adapter_take (demux->adapter, demux->neededbytes);
2247 /* Put data in a buffer, set timestamps, caps, ... */
2248 outbuf = gst_buffer_new ();
2249 gst_buffer_set_data (outbuf, data, demux->neededbytes);
2250 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
2251 GST_FOURCC_ARGS (stream->fourcc));
2253 if (stream->samples[stream->sample_index].pts_offset) {
2254 demux->last_ts = stream->samples[stream->sample_index].timestamp;
2255 GST_BUFFER_TIMESTAMP (outbuf) = demux->last_ts +
2256 stream->samples[stream->sample_index].pts_offset;
2258 GST_BUFFER_TIMESTAMP (outbuf) =
2259 stream->samples[stream->sample_index].timestamp;
2260 demux->last_ts = GST_BUFFER_TIMESTAMP (outbuf);
2262 GST_BUFFER_DURATION (outbuf) =
2263 stream->samples[stream->sample_index].duration;
2267 GST_LOG_OBJECT (demux,
2268 "Pushing buffer with time %" GST_TIME_FORMAT " on pad %p",
2269 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)), stream->pad);
2270 gst_buffer_set_caps (outbuf, stream->caps);
2271 ret = gst_pad_push (stream->pad, outbuf);
2273 gst_buffer_unref (outbuf);
2278 ret = gst_qtdemux_combine_flows (demux, stream, ret);
2280 stream->sample_index++;
2282 /* update current offset and figure out size of next buffer */
2283 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
2284 demux->offset, demux->neededbytes);
2285 demux->offset += demux->neededbytes;
2286 GST_LOG_OBJECT (demux, "offset is now %lld", demux->offset);
2288 if ((demux->neededbytes = next_entry_size (demux)) == -1)
2297 /* when buffering movie data, at least show user something is happening */
2298 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
2299 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
2300 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
2301 demux->neededbytes);
2304 gst_object_unref (demux);
2311 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
2312 ret = GST_FLOW_ERROR;
2317 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
2318 ret = GST_FLOW_UNEXPECTED;
2323 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
2324 (NULL), ("qtdemuxer invalid state %d", demux->state));
2325 ret = GST_FLOW_ERROR;
2331 qtdemux_sink_activate (GstPad * sinkpad)
2333 if (gst_pad_check_pull_range (sinkpad))
2334 return gst_pad_activate_pull (sinkpad, TRUE);
2336 return gst_pad_activate_push (sinkpad, TRUE);
2340 qtdemux_sink_activate_pull (GstPad * sinkpad, gboolean active)
2342 GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad));
2345 demux->pullbased = TRUE;
2346 demux->segment_running = TRUE;
2347 return gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
2350 demux->segment_running = FALSE;
2351 return gst_pad_stop_task (sinkpad);
2356 qtdemux_sink_activate_push (GstPad * sinkpad, gboolean active)
2358 GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad));
2360 demux->pullbased = FALSE;
2367 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
2369 return g_malloc (items * size);
2373 qtdemux_zfree (void *opaque, void *addr)
2379 qtdemux_inflate (void *z_buffer, int z_length, int length)
2385 z = g_new0 (z_stream, 1);
2386 z->zalloc = qtdemux_zalloc;
2387 z->zfree = qtdemux_zfree;
2390 z->next_in = z_buffer;
2391 z->avail_in = z_length;
2393 buffer = (guint8 *) g_malloc (length);
2394 ret = inflateInit (z);
2395 while (z->avail_in > 0) {
2396 if (z->avail_out == 0) {
2398 buffer = (guint8 *) g_realloc (buffer, length);
2399 z->next_out = buffer + z->total_out;
2400 z->avail_out = 1024;
2402 ret = inflate (z, Z_SYNC_FLUSH);
2406 if (ret != Z_STREAM_END) {
2407 g_warning ("inflate() returned %d", ret);
2413 #endif /* HAVE_ZLIB */
2416 qtdemux_parse_moov (GstQTDemux * qtdemux, guint8 * buffer, int length)
2420 qtdemux->moov_node = g_node_new (buffer);
2422 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
2423 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
2425 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
2431 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
2432 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
2433 if (dcom == NULL || cmvd == NULL)
2434 goto invalid_compression;
2436 method = QT_FOURCC ((guint8 *) dcom->data + 8);
2439 case GST_MAKE_FOURCC ('z', 'l', 'i', 'b'):{
2440 int uncompressed_length;
2441 int compressed_length;
2444 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
2445 compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12;
2446 GST_LOG ("length = %d", uncompressed_length);
2449 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
2450 compressed_length, uncompressed_length);
2452 qtdemux->moov_node_compressed = qtdemux->moov_node;
2453 qtdemux->moov_node = g_node_new (buf);
2455 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
2456 uncompressed_length);
2459 #endif /* HAVE_ZLIB */
2461 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
2462 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
2469 invalid_compression:
2471 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
2477 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, guint8 * buf,
2484 if (buf + 4 > end) {
2485 GST_LOG_OBJECT (qtdemux, "buffer overrun");
2488 len = QT_UINT32 (buf);
2490 GST_LOG_OBJECT (qtdemux, "empty container");
2494 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
2497 if (len > (end - buf)) {
2498 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len, end - buf);
2502 child = g_node_new (buf);
2503 g_node_append (node, child);
2504 qtdemux_parse_node (qtdemux, child, buf, len);
2512 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
2515 int len = QT_UINT32 (xdxt->data);
2516 guint8 *buf = xdxt->data;
2517 guint8 *end = buf + len;
2520 /* skip size and type */
2528 size = QT_UINT32 (buf);
2529 type = QT_FOURCC (buf + 4);
2531 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
2533 if (buf + size > end || size <= 0)
2539 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
2540 GST_FOURCC_ARGS (type));
2544 buffer = gst_buffer_new_and_alloc (size);
2545 memcpy (GST_BUFFER_DATA (buffer), buf, size);
2546 stream->buffers = g_slist_append (stream->buffers, buffer);
2547 GST_LOG_OBJECT (qtdemux, "parsing theora header");
2550 buffer = gst_buffer_new_and_alloc (size);
2551 memcpy (GST_BUFFER_DATA (buffer), buf, size);
2552 stream->buffers = g_slist_append (stream->buffers, buffer);
2553 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
2556 buffer = gst_buffer_new_and_alloc (size);
2557 memcpy (GST_BUFFER_DATA (buffer), buf, size);
2558 stream->buffers = g_slist_append (stream->buffers, buffer);
2559 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
2562 GST_WARNING_OBJECT (qtdemux,
2563 "unknown theora cookie %" GST_FOURCC_FORMAT,
2564 GST_FOURCC_ARGS (type));
2573 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, guint8 * buffer,
2577 guint32 node_length;
2578 const QtNodeType *type;
2581 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %d", buffer, length);
2583 node_length = QT_UINT32 (buffer);
2584 fourcc = QT_FOURCC (buffer + 4);
2586 type = qtdemux_type_get (fourcc);
2588 /* ignore empty nodes */
2589 if (fourcc == 0 || node_length == 8)
2592 end = buffer + length;
2594 GST_LOG_OBJECT (qtdemux,
2595 "parsing '%" GST_FOURCC_FORMAT "', length=%d, name '%s'",
2596 GST_FOURCC_ARGS (fourcc), node_length, type->name);
2598 if (type->flags & QT_FLAG_CONTAINER) {
2599 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
2604 if (node_length < 20) {
2605 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
2608 GST_DEBUG_OBJECT (qtdemux,
2609 "parsing stsd (sample table, sample description) atom");
2610 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
2619 /* small boxes are also inside wave inside the mp4a box */
2620 GST_LOG_OBJECT (qtdemux, "skipping small mp4a box");
2623 version = QT_UINT32 (buffer + 16);
2625 GST_WARNING_OBJECT (qtdemux, "mp4a version 0x%08x", version);
2627 /* parse any esds descriptors */
2639 GST_WARNING_OBJECT (qtdemux, "unhandled mp4a version 0x%08x",
2645 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
2654 GST_DEBUG_OBJECT (qtdemux, "parsing in mp4v");
2655 version = QT_UINT32 (buffer + 16);
2656 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
2657 if (1 || version == 0x00000000) {
2658 buf = buffer + 0x32;
2660 /* FIXME Quicktime uses PASCAL string while
2661 * the iso format uses C strings. Check the file
2662 * type before attempting to parse the string here. */
2663 tlen = QT_UINT8 (buf);
2664 GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
2666 GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
2667 /* the string has a reserved space of 32 bytes so skip
2668 * the remaining 31 */
2670 buf += 4; /* and 4 bytes reserved */
2672 qtdemux_dump_mem (buf, end - buf);
2674 qtdemux_parse_container (qtdemux, node, buf, end);
2680 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
2685 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
2686 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
2694 version = QT_UINT32 (buffer + 12);
2695 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
2702 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
2707 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
2714 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT,
2715 GST_FOURCC_ARGS (fourcc));
2720 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
2724 guint32 child_fourcc;
2726 for (child = g_node_first_child (node); child;
2727 child = g_node_next_sibling (child)) {
2728 buffer = (guint8 *) child->data;
2730 child_fourcc = QT_FOURCC (buffer + 4);
2732 if (child_fourcc == fourcc) {
2740 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
2744 guint32 child_fourcc;
2746 for (child = g_node_next_sibling (node); child;
2747 child = g_node_next_sibling (child)) {
2748 buffer = (guint8 *) child->data;
2750 child_fourcc = QT_FOURCC (buffer + 4);
2752 if (child_fourcc == fourcc) {
2760 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
2761 QtDemuxStream * stream, GstTagList * list)
2763 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
2764 goto too_many_streams;
2766 if (stream->subtype == FOURCC_vide) {
2767 gchar *name = g_strdup_printf ("video_%02d", qtdemux->n_video_streams);
2770 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
2773 /* fps is calculated base on the duration of the first frames since
2774 * qt does not have a fixed framerate. */
2775 if ((stream->n_samples == 1) && (stream->min_duration == 0)) {
2780 stream->fps_n = stream->timescale;
2781 if (stream->min_duration == 0)
2784 stream->fps_d = stream->min_duration;
2789 gint depth, palette_count;
2790 const guint32 *palette_data = NULL;
2792 gst_caps_set_simple (stream->caps,
2793 "width", G_TYPE_INT, stream->width,
2794 "height", G_TYPE_INT, stream->height,
2795 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
2797 depth = stream->bits_per_sample;
2799 /* more than 32 bits means grayscale */
2800 gray = (depth > 32);
2801 /* low 32 bits specify the depth */
2804 /* different number of palette entries is determined by depth. */
2806 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
2807 palette_count = (1 << depth);
2809 switch (palette_count) {
2813 palette_data = ff_qt_default_palette_2;
2816 palette_data = ff_qt_default_palette_4;
2820 palette_data = ff_qt_grayscale_palette_16;
2822 palette_data = ff_qt_default_palette_16;
2826 palette_data = ff_qt_grayscale_palette_256;
2828 palette_data = ff_qt_default_palette_256;
2831 GST_ELEMENT_WARNING (qtdemux, STREAM, DECODE,
2832 (_("The video in this file might not play correctly.")),
2833 ("unsupported palette depth %d", depth));
2839 /* make sure it's not writable. We leave MALLOCDATA to NULL so that we
2840 * don't free any of the buffer data. */
2841 palette = gst_buffer_new ();
2842 GST_BUFFER_FLAG_SET (palette, GST_BUFFER_FLAG_READONLY);
2843 GST_BUFFER_DATA (palette) = (guint8 *) palette_data;
2844 GST_BUFFER_SIZE (palette) = sizeof (guint32) * palette_count;
2846 gst_caps_set_simple (stream->caps, "palette_data",
2847 GST_TYPE_BUFFER, palette, NULL);
2848 gst_buffer_unref (palette);
2849 } else if (palette_count != 0) {
2850 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
2851 (NULL), ("Unsupported palette depth %d. Ignoring stream.", depth));
2853 gst_object_unref (stream->pad);
2857 qtdemux->n_video_streams++;
2858 } else if (stream->subtype == FOURCC_soun) {
2859 gchar *name = g_strdup_printf ("audio_%02d", qtdemux->n_audio_streams);
2862 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
2865 gst_caps_set_simple (stream->caps,
2866 "rate", G_TYPE_INT, (int) stream->rate,
2867 "channels", G_TYPE_INT, stream->n_channels, NULL);
2869 qtdemux->n_audio_streams++;
2870 } else if (stream->subtype == FOURCC_strm) {
2871 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
2873 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
2877 qtdemux->streams[qtdemux->n_streams] = stream;
2878 qtdemux->n_streams++;
2879 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
2882 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
2884 gst_pad_use_fixed_caps (stream->pad);
2885 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
2886 gst_pad_set_query_type_function (stream->pad,
2887 gst_qtdemux_get_src_query_types);
2888 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
2890 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
2891 gst_pad_set_caps (stream->pad, stream->caps);
2893 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
2894 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
2895 gst_pad_set_active (stream->pad, TRUE);
2896 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
2898 gst_element_found_tags_for_pad (GST_ELEMENT_CAST (qtdemux), stream->pad,
2906 GST_ELEMENT_WARNING (qtdemux, STREAM, DECODE,
2907 (_("This file contains too many streams. Only playing first %d"),
2908 GST_QTDEMUX_MAX_STREAMS), (NULL));
2913 /* collect all samples for @stream by reading the info from @stbl
2916 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream,
2927 const guint8 *stsc_data, *stsz_data, *stco_data;
2931 int n_samples_per_chunk;
2933 QtDemuxSample *samples;
2936 guint64 timestamp, time;
2938 /* sample to chunk */
2939 if (!(stsc = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsc)))
2941 stsc_data = (const guint8 *) stsc->data;
2943 if (!(stsz = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsz)))
2945 stsz_data = (const guint8 *) stsz->data;
2947 stco = qtdemux_tree_get_child_by_type (stbl, FOURCC_stco);
2948 co64 = qtdemux_tree_get_child_by_type (stbl, FOURCC_co64);
2950 stco_data = (const guint8 *) stco->data;
2957 if (!(stts = qtdemux_tree_get_child_by_type (stbl, FOURCC_stts)))
2960 /* sample sync, can be NULL */
2961 stss = qtdemux_tree_get_child_by_type (stbl, FOURCC_stss);
2963 sample_size = QT_UINT32 (stsz_data + 12);
2964 if (sample_size == 0 || stream->sampled) {
2965 n_samples = QT_UINT32 (stsz_data + 16);
2966 GST_DEBUG_OBJECT (qtdemux, "stsz sample_size 0, allocating n_samples %d",
2968 stream->n_samples = n_samples;
2969 samples = g_new0 (QtDemuxSample, n_samples);
2970 stream->samples = samples;
2972 for (i = 0; i < n_samples; i++) {
2973 if (sample_size == 0)
2974 samples[i].size = QT_UINT32 (stsz_data + i * 4 + 20);
2976 samples[i].size = sample_size;
2978 GST_LOG_OBJECT (qtdemux, "sample %d has size %d", i, samples[i].size);
2979 /* init other fields to defaults for this sample */
2980 samples[i].keyframe = FALSE;
2982 n_samples_per_chunk = QT_UINT32 (stsc_data + 12);
2984 for (i = 0; i < n_samples_per_chunk; i++) {
2985 guint32 first_chunk, last_chunk;
2986 guint32 samples_per_chunk;
2988 first_chunk = QT_UINT32 (stsc_data + 16 + i * 12 + 0) - 1;
2989 if (i == n_samples_per_chunk - 1) {
2990 last_chunk = G_MAXUINT32;
2992 last_chunk = QT_UINT32 (stsc_data + 16 + i * 12 + 12) - 1;
2994 samples_per_chunk = QT_UINT32 (stsc_data + 16 + i * 12 + 4);
2996 for (j = first_chunk; j < last_chunk; j++) {
2997 guint64 chunk_offset;
3000 chunk_offset = QT_UINT32 (stco_data + 16 + j * 4);
3002 chunk_offset = QT_UINT64 ((guint8 *) co64->data + 16 + j * 8);
3004 for (k = 0; k < samples_per_chunk; k++) {
3005 GST_LOG_OBJECT (qtdemux, "Creating entry %d with offset %lld",
3006 index, chunk_offset);
3007 samples[index].chunk = j;
3008 samples[index].offset = chunk_offset;
3009 chunk_offset += samples[index].size;
3011 if (index >= n_samples)
3018 n_sample_times = QT_UINT32 ((guint8 *) stts->data + 12);
3020 stream->min_duration = 0;
3023 for (i = 0; i < n_sample_times; i++) {
3027 n = QT_UINT32 ((guint8 *) stts->data + 16 + 8 * i);
3028 duration = QT_UINT32 ((guint8 *) stts->data + 16 + 8 * i + 4);
3029 for (j = 0; j < n; j++) {
3030 GST_DEBUG_OBJECT (qtdemux, "sample %d: timestamp %" GST_TIME_FORMAT,
3031 index, GST_TIME_ARGS (timestamp));
3033 samples[index].timestamp = timestamp;
3034 /* take first duration for fps */
3035 if (stream->min_duration == 0)
3036 stream->min_duration = duration;
3037 /* add non-scaled values to avoid rounding errors */
3039 timestamp = gst_util_uint64_scale (time, GST_SECOND, stream->timescale);
3040 samples[index].duration = timestamp - samples[index].timestamp;
3046 /* mark keyframes */
3047 guint32 n_sample_syncs;
3049 n_sample_syncs = QT_UINT32 ((guint8 *) stss->data + 12);
3050 if (n_sample_syncs == 0) {
3051 stream->all_keyframe = TRUE;
3054 for (i = 0; i < n_sample_syncs; i++) {
3055 /* note that the first sample is index 1, not 0 */
3056 index = QT_UINT32 ((guint8 *) stss->data + offset);
3058 samples[index - 1].keyframe = TRUE;
3064 /* no stss, all samples are keyframes */
3065 stream->all_keyframe = TRUE;
3068 GST_DEBUG_OBJECT (qtdemux,
3069 "stsz sample_size %d != 0, treating chunks as samples", sample_size);
3071 /* treat chunks as samples */
3073 n_samples = QT_UINT32 (stco_data + 12);
3075 n_samples = QT_UINT32 ((guint8 *) co64->data + 12);
3077 stream->n_samples = n_samples;
3078 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %d", n_samples);
3079 samples = g_new0 (QtDemuxSample, n_samples);
3080 stream->samples = samples;
3082 n_samples_per_chunk = QT_UINT32 (stsc_data + 12);
3083 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %d", n_samples_per_chunk);
3086 for (i = 0; i < n_samples_per_chunk; i++) {
3087 guint32 first_chunk, last_chunk;
3088 guint32 samples_per_chunk;
3090 first_chunk = QT_UINT32 (stsc_data + 16 + i * 12 + 0) - 1;
3091 /* the last chunk of each entry is calculated by taking the first chunk
3092 * of the next entry; except if there is no next, where we fake it with
3094 if (i == n_samples_per_chunk - 1) {
3095 last_chunk = G_MAXUINT32;
3097 last_chunk = QT_UINT32 (stsc_data + 16 + i * 12 + 12) - 1;
3099 samples_per_chunk = QT_UINT32 (stsc_data + 16 + i * 12 + 4);
3101 GST_LOG_OBJECT (qtdemux,
3102 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
3103 first_chunk, last_chunk, samples_per_chunk);
3105 for (j = first_chunk; j < last_chunk; j++) {
3106 guint64 chunk_offset;
3112 chunk_offset = QT_UINT32 (stco_data + 16 + j * 4);
3114 chunk_offset = QT_UINT64 ((guint8 *) co64->data + 16 + j * 8);
3116 GST_LOG_OBJECT (qtdemux,
3117 "Creating entry %d with offset %" G_GUINT64_FORMAT, j,
3120 samples[j].chunk = j;
3121 samples[j].offset = chunk_offset;
3123 if (stream->samples_per_frame * stream->bytes_per_frame) {
3124 samples[j].size = (samples_per_chunk * stream->n_channels) /
3125 stream->samples_per_frame * stream->bytes_per_frame;
3127 samples[j].size = samples_per_chunk;
3130 GST_DEBUG_OBJECT (qtdemux, "sample %d: timestamp %" GST_TIME_FORMAT
3131 ", size %u", j, GST_TIME_ARGS (timestamp), samples[j].size);
3133 samples[j].timestamp = timestamp;
3134 sample_index += samples_per_chunk;
3136 timestamp = gst_util_uint64_scale (sample_index,
3137 GST_SECOND, stream->timescale);
3138 samples[j].duration = timestamp - samples[j].timestamp;
3140 samples[j].keyframe = TRUE;
3145 /* composition time to sample */
3146 if ((ctts = qtdemux_tree_get_child_by_type (stbl, FOURCC_ctts))) {
3147 const guint8 *ctts_data = (const guint8 *) ctts->data;
3148 guint32 n_entries = QT_UINT32 (ctts_data + 12);
3152 /* Fill in the pts_offsets */
3153 for (i = 0, j = 0; (j < stream->n_samples) && (i < n_entries); i++) {
3154 count = QT_UINT32 (ctts_data + 16 + i * 8);
3155 soffset = QT_UINT32 (ctts_data + 20 + i * 8);
3156 for (k = 0; k < count; k++, j++) {
3157 /* we operate with very small soffset values here, it shouldn't overflow */
3158 samples[j].pts_offset = soffset * GST_SECOND / stream->timescale;
3168 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
3169 (_("This file is corrupt and cannot be played.")), (NULL));
3174 /* collect all segment info for @stream.
3177 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
3182 /* parse and prepare segment info from the edit list */
3183 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
3184 stream->n_segments = 0;
3185 stream->segments = NULL;
3186 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
3190 guint64 time, stime;
3193 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
3194 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
3197 buffer = elst->data;
3199 n_segments = QT_UINT32 (buffer + 12);
3201 /* we might allocate a bit too much, at least allocate 1 segment */
3202 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
3204 /* segments always start from 0 */
3208 for (i = 0; i < n_segments; i++) {
3211 QtDemuxSegment *segment;
3213 media_time = QT_UINT32 (buffer + 20 + i * 12);
3215 /* -1 media time is an empty segment, just ignore it */
3216 if (media_time == G_MAXUINT32)
3219 duration = QT_UINT32 (buffer + 16 + i * 12);
3221 segment = &stream->segments[count++];
3223 /* time and duration expressed in global timescale */
3224 segment->time = stime;
3225 /* add non scaled values so we don't cause roundoff errors */
3227 stime = gst_util_uint64_scale (time, GST_SECOND, qtdemux->timescale);
3228 segment->stop_time = stime;
3229 segment->duration = stime - segment->time;
3230 /* media_time expressed in stream timescale */
3231 segment->media_start =
3232 gst_util_uint64_scale (media_time, GST_SECOND, stream->timescale);
3233 segment->media_stop = segment->media_start + segment->duration;
3234 segment->rate = QT_FP32 (buffer + 24 + i * 12);
3236 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
3237 ", duration %" GST_TIME_FORMAT ", media_time %" GST_TIME_FORMAT
3238 ", rate %g", i, GST_TIME_ARGS (segment->time),
3239 GST_TIME_ARGS (segment->duration),
3240 GST_TIME_ARGS (segment->media_start), segment->rate);
3242 GST_DEBUG_OBJECT (qtdemux, "found %d non-empty segments", count);
3243 stream->n_segments = count;
3247 /* no segments, create one to play the complete trak */
3248 if (stream->n_segments == 0) {
3249 if (stream->segments == NULL)
3250 stream->segments = g_new (QtDemuxSegment, 1);
3252 stream->segments[0].time = 0;
3253 stream->segments[0].stop_time = qtdemux->segment.duration;
3254 stream->segments[0].duration = qtdemux->segment.duration;
3255 stream->segments[0].media_start = 0;
3256 stream->segments[0].media_stop = qtdemux->segment.duration;
3257 stream->segments[0].rate = 1.0;
3259 GST_DEBUG_OBJECT (qtdemux, "created dummy segment");
3260 stream->n_segments = 1;
3262 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
3268 * With each track we associate a new QtDemuxStream that contains all the info
3270 * traks that do not decode to something (like strm traks) will not have a pad.
3273 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
3287 QtDemuxStream *stream;
3288 GstTagList *list = NULL;
3289 gchar *codec = NULL;
3290 const guint8 *stsd_data;
3293 stream = g_new0 (QtDemuxStream, 1);
3294 /* new streams always need a discont */
3295 stream->discont = TRUE;
3296 /* we enable clipping for raw audio/video streams */
3297 stream->need_clip = FALSE;
3298 stream->segment_index = -1;
3299 stream->time_position = 0;
3300 stream->sample_index = -1;
3301 stream->last_ret = GST_FLOW_OK;
3303 if (!(tkhd = qtdemux_tree_get_child_by_type (trak, FOURCC_tkhd)))
3306 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags: 0x%08x",
3307 QT_UINT32 ((guint8 *) tkhd->data + 8));
3309 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
3312 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
3313 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
3314 if (qtdemux->major_brand != FOURCC_mjp2 ||
3315 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
3319 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
3320 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
3321 if (version == 0x01000000) {
3322 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
3323 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
3325 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
3326 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
3329 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
3331 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
3334 if (qtdemux->duration != G_MAXINT32 && stream->duration != G_MAXINT32) {
3335 guint64 tdur1, tdur2;
3337 /* don't overflow */
3338 tdur1 = stream->timescale * (guint64) qtdemux->duration;
3339 tdur2 = qtdemux->timescale * (guint64) stream->duration;
3342 * some of those trailers, nowadays, have prologue images that are
3343 * themselves vide tracks as well. I haven't really found a way to
3344 * identify those yet, except for just looking at their duration. */
3345 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
3346 GST_WARNING_OBJECT (qtdemux,
3347 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
3348 " vs. %" G_GUINT32_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
3349 "found, assuming preview image or something; skipping track",
3350 stream->duration, stream->timescale, qtdemux->duration,
3351 qtdemux->timescale);
3357 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
3360 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
3361 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
3363 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
3364 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
3365 GST_FOURCC_ARGS (stream->subtype));
3367 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
3370 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
3374 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
3376 stsd_data = (const guint8 *) stsd->data;
3378 if (stream->subtype == FOURCC_vide) {
3381 stream->sampled = TRUE;
3384 stream->fourcc = fourcc = QT_FOURCC (stsd_data + offset + 4);
3385 GST_LOG_OBJECT (qtdemux, "st type: %" GST_FOURCC_FORMAT,
3386 GST_FOURCC_ARGS (fourcc));
3388 stream->width = QT_UINT16 (stsd_data + offset + 32);
3389 stream->height = QT_UINT16 (stsd_data + offset + 34);
3390 stream->fps_n = 0; /* this is filled in later */
3391 stream->fps_d = 0; /* this is filled in later */
3392 stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
3393 stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
3395 GST_LOG_OBJECT (qtdemux, "frame count: %u",
3396 QT_UINT16 (stsd_data + offset + 48));
3398 if (fourcc == FOURCC_drms)
3399 goto error_encrypted;
3402 qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
3404 list = gst_tag_list_new ();
3405 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
3406 GST_TAG_VIDEO_CODEC, codec, NULL);
3412 mp4v = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4v);
3414 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
3417 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
3422 gint len = QT_UINT32 (stsd_data) - 0x66;
3423 const guint8 *avc_data = stsd_data + 0x66;
3426 while (len >= 0x8 &&
3427 QT_FOURCC (avc_data + 0x4) != FOURCC_avcC &&
3428 QT_UINT32 (avc_data) < len) {
3429 len -= QT_UINT32 (avc_data);
3430 avc_data += QT_UINT32 (avc_data);
3433 /* parse, if found */
3434 if (len > 0x8 && QT_FOURCC (avc_data + 0x4) == FOURCC_avcC) {
3438 if (QT_UINT32 (avc_data) < len)
3439 size = QT_UINT32 (avc_data) - 0x8;
3443 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
3445 buf = gst_buffer_new_and_alloc (size);
3446 memcpy (GST_BUFFER_DATA (buf), avc_data + 0x8, size);
3447 gst_caps_set_simple (stream->caps,
3448 "codec_data", GST_TYPE_BUFFER, buf, NULL);
3449 gst_buffer_unref (buf);
3455 GNode *jp2h, *colr, *mjp2, *field, *prefix;
3459 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
3460 /* some required atoms */
3461 mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
3464 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
3467 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
3470 GST_DEBUG_OBJECT (qtdemux, "found colr");
3471 /* try to extract colour space info */
3472 if (QT_UINT8 (colr->data + 8) == 1) {
3473 switch (QT_UINT32 (colr->data + 11)) {
3475 fourcc = GST_MAKE_FOURCC ('s', 'R', 'G', 'B');
3478 fourcc = GST_MAKE_FOURCC ('G', 'R', 'A', 'Y');
3481 fourcc = GST_MAKE_FOURCC ('s', 'Y', 'U', 'V');
3489 gst_caps_set_simple (stream->caps,
3490 "fourcc", GST_TYPE_FOURCC, fourcc, NULL);
3492 /* some optional atoms */
3493 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
3494 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
3496 /* indicate possible fields in caps */
3498 data = field->data + 8;
3500 gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
3501 (gint) * data, NULL);
3503 /* add codec_data if provided */
3508 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
3509 data = prefix->data;
3510 len = QT_UINT32 (data);
3513 buf = gst_buffer_new_and_alloc (len);
3514 memcpy (GST_BUFFER_DATA (buf), data + 8, len);
3515 gst_caps_set_simple (stream->caps,
3516 "codec_data", GST_TYPE_BUFFER, buf, NULL);
3517 gst_buffer_unref (buf);
3526 gint len = QT_UINT32 (stsd_data);
3528 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
3530 buf = gst_buffer_new_and_alloc (len);
3531 memcpy (GST_BUFFER_DATA (buf), stsd_data, len);
3532 gst_caps_set_simple (stream->caps,
3533 "codec_data", GST_TYPE_BUFFER, buf, NULL);
3534 gst_buffer_unref (buf);
3539 gst_caps_set_simple (stream->caps,
3540 "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
3547 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
3548 xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
3552 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
3556 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
3557 /* collect the headers and store them in a stream list so that we can
3558 * send them out first */
3559 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
3567 GST_INFO_OBJECT (qtdemux,
3568 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
3569 GST_FOURCC_ARGS (fourcc), stream->caps);
3571 } else if (stream->subtype == FOURCC_soun) {
3572 int version, samplesize;
3575 guint16 compression_id;
3577 len = QT_UINT32 (stsd_data + 16);
3578 GST_LOG_OBJECT (qtdemux, "stsd len: %d", len);
3580 stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
3581 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
3582 GST_FOURCC_ARGS (stream->fourcc));
3586 version = QT_UINT32 (stsd_data + offset);
3587 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
3588 samplesize = QT_UINT16 (stsd_data + offset + 10);
3589 compression_id = QT_UINT16 (stsd_data + offset + 12);
3590 stream->rate = QT_FP32 (stsd_data + offset + 16);
3592 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
3593 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
3594 QT_UINT32 (stsd_data + offset + 4));
3595 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
3596 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
3597 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
3598 GST_LOG_OBJECT (qtdemux, "packet size: %d",
3599 QT_UINT16 (stsd_data + offset + 14));
3600 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
3602 if (compression_id == 0xfffe)
3603 stream->sampled = TRUE;
3605 /* first assume uncompressed audio */
3606 stream->bytes_per_sample = samplesize / 8;
3607 stream->samples_per_frame = stream->n_channels;
3608 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
3609 stream->samples_per_packet = stream->samples_per_frame;
3610 stream->bytes_per_packet = stream->bytes_per_sample;
3614 /* Yes, these have to be hard-coded */
3617 stream->samples_per_packet = 6;
3618 stream->bytes_per_packet = 1;
3619 stream->bytes_per_frame = 1 * stream->n_channels;
3620 stream->bytes_per_sample = 1;
3621 stream->samples_per_frame = 6 * stream->n_channels;
3626 stream->samples_per_packet = 3;
3627 stream->bytes_per_packet = 1;
3628 stream->bytes_per_frame = 1 * stream->n_channels;
3629 stream->bytes_per_sample = 1;
3630 stream->samples_per_frame = 3 * stream->n_channels;
3635 stream->samples_per_packet = 64;
3636 stream->bytes_per_packet = 34;
3637 stream->bytes_per_frame = 34 * stream->n_channels;
3638 stream->bytes_per_sample = 2;
3639 stream->samples_per_frame = 64 * stream->n_channels;
3645 stream->samples_per_packet = 1;
3646 stream->bytes_per_packet = 1;
3647 stream->bytes_per_frame = 1 * stream->n_channels;
3648 stream->bytes_per_sample = 1;
3649 stream->samples_per_frame = 1 * stream->n_channels;
3655 if (version == 0x00010000) {
3663 /* only parse extra decoding config for non-pcm audio */
3664 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
3665 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
3666 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
3667 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
3669 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
3670 stream->samples_per_packet);
3671 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
3672 stream->bytes_per_packet);
3673 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
3674 stream->bytes_per_frame);
3675 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
3676 stream->bytes_per_sample);
3678 if (!stream->sampled && stream->bytes_per_packet) {
3679 stream->samples_per_frame = (stream->bytes_per_frame /
3680 stream->bytes_per_packet) * stream->samples_per_packet;
3681 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
3682 stream->samples_per_frame);
3688 } else if (version == 0x00020000) {
3695 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
3696 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
3697 stream->rate = qtfp.fp;
3698 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
3700 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
3701 stream->samples_per_packet);
3702 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
3703 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
3707 GST_WARNING_OBJECT (qtdemux, "unknown version %08x", version);
3710 if (fourcc == FOURCC_drms)
3711 goto error_encrypted;
3713 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc, NULL, 0,
3717 list = gst_tag_list_new ();
3718 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
3719 GST_TAG_AUDIO_CODEC, codec, NULL);
3724 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
3728 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
3730 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
3732 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
3736 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
3740 /* FIXME: what is in the chunk? */
3743 gint len = QT_UINT32 (stsd_data);
3745 /* seems to be always = 116 = 0x74 */
3751 gint len = QT_UINT32 (stsd_data);
3754 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
3756 memcpy (GST_BUFFER_DATA (buf), stsd_data + 0x4C, len - 0x4C);
3757 gst_caps_set_simple (stream->caps,
3758 "codec_data", GST_TYPE_BUFFER, buf, NULL);
3759 gst_buffer_unref (buf);
3761 gst_caps_set_simple (stream->caps,
3762 "samplesize", G_TYPE_INT, samplesize, NULL);
3767 gint len = QT_UINT32 (stsd_data);
3770 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
3772 memcpy (GST_BUFFER_DATA (buf), stsd_data + 0x34, len - 0x34);
3773 gst_caps_set_simple (stream->caps,
3774 "codec_data", GST_TYPE_BUFFER, buf, NULL);
3775 gst_buffer_unref (buf);
3777 gst_caps_set_simple (stream->caps,
3778 "samplesize", G_TYPE_INT, samplesize, NULL);
3783 gint len = QT_UINT32 (stsd_data);
3786 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
3788 memcpy (GST_BUFFER_DATA (buf), stsd_data + 0x34, len - 0x34);
3790 gst_caps_set_simple (stream->caps,
3791 "codec_data", GST_TYPE_BUFFER, buf, NULL);
3792 gst_buffer_unref (buf);
3800 GST_INFO_OBJECT (qtdemux,
3801 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
3802 GST_FOURCC_ARGS (fourcc), stream->caps);
3804 } else if (stream->subtype == FOURCC_strm) {
3807 stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
3808 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
3809 GST_FOURCC_ARGS (fourcc));
3811 if (fourcc != FOURCC_rtsp) {
3812 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
3813 GST_FOURCC_ARGS (fourcc));
3814 goto unknown_stream;
3816 stream->sampled = TRUE;
3818 goto unknown_stream;
3821 /* promote to sampled format */
3822 if (stream->fourcc == FOURCC_samr) {
3823 /* force mono 8000 Hz for AMR */
3824 stream->sampled = TRUE;
3825 stream->n_channels = 1;
3826 stream->rate = 8000;
3827 } else if (stream->fourcc == FOURCC_sawb) {
3828 /* force mono 16000 Hz for AMR-WB */
3829 stream->sampled = TRUE;
3830 stream->n_channels = 1;
3831 stream->rate = 16000;
3832 } else if (stream->fourcc == FOURCC_mp4a) {
3833 stream->sampled = TRUE;
3836 /* collect sample information */
3837 if (!qtdemux_parse_samples (qtdemux, stream, stbl))
3838 goto samples_failed;
3840 /* configure segments */
3841 if (!qtdemux_parse_segments (qtdemux, stream, trak))
3842 goto segments_failed;
3844 /* now we are ready to add the stream */
3845 gst_qtdemux_add_stream (qtdemux, stream, list);
3852 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
3853 (_("This file is corrupt and cannot be played.")), (NULL));
3859 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
3865 /* we posted an error already */
3871 /* we posted an error already */
3877 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
3878 GST_FOURCC_ARGS (stream->subtype));
3885 qtdemux_tag_add_str (GstQTDemux * qtdemux, const char *tag, const char *dummy,
3888 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
3895 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
3897 len = QT_UINT32 (data->data);
3898 type = QT_UINT32 ((guint8 *) data->data + 8);
3899 if (type == 0x00000001) {
3900 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
3903 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
3904 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s,
3908 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
3912 len = QT_UINT32 (node->data);
3913 type = QT_UINT32 ((guint8 *) node->data + 4);
3914 if (type & 0xa9000000) {
3915 /* Type starts with the (C) symbol, so the next 32 bits are
3916 * the language code, which we ignore */
3918 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
3921 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
3923 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
3924 len - offset, env_vars);
3926 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
3927 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s, NULL);
3930 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
3936 qtdemux_tag_add_num (GstQTDemux * qtdemux, const char *tag1,
3937 const char *tag2, GNode * node)
3944 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
3946 len = QT_UINT32 (data->data);
3947 type = QT_UINT32 ((guint8 *) data->data + 8);
3948 if (type == 0x00000000 && len >= 22) {
3949 n1 = QT_UINT16 ((guint8 *) data->data + 18);
3950 n2 = QT_UINT16 ((guint8 *) data->data + 20);
3951 GST_DEBUG_OBJECT (qtdemux, "adding tag %d/%d", n1, n2);
3952 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
3953 tag1, n1, tag2, n2, NULL);
3959 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
3967 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
3969 len = QT_UINT32 (data->data);
3970 type = QT_UINT32 ((guint8 *) data->data + 8);
3971 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
3972 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
3973 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
3974 n1 = QT_UINT16 ((guint8 *) data->data + 16);
3976 /* do not add bpm=0 */
3977 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
3978 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
3979 tag1, (gdouble) n1, NULL);
3986 qtdemux_tag_add_covr (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
3994 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
3996 len = QT_UINT32 (data->data);
3997 type = QT_UINT32 ((guint8 *) data->data + 8);
3998 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
3999 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
4000 if ((buf = gst_tag_image_data_to_image_buffer (data->data + 16, len - 16,
4001 GST_TAG_IMAGE_TYPE_NONE))) {
4002 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
4003 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
4011 qtdemux_tag_add_date (GstQTDemux * qtdemux, const char *tag, const char *dummy,
4019 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
4021 len = QT_UINT32 (data->data);
4022 type = QT_UINT32 ((guint8 *) data->data + 8);
4023 if (type == 0x00000001) {
4024 guint y, m = 1, d = 1;
4027 s = g_strndup ((char *) data->data + 16, len - 16);
4028 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
4029 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
4030 if (ret >= 1 && y > 1500 && y < 3000) {
4033 date = g_date_new_dmy (d, m, y);
4034 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag,
4038 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
4046 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, const char *tag, const char *dummy,
4049 static const gchar *genres[] = {
4050 "N/A", "Blues", "Classic Rock", "Country", "Dance", "Disco",
4051 "Funk", "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies",
4052 "Other", "Pop", "R&B", "Rap", "Reggae", "Rock", "Techno",
4053 "Industrial", "Alternative", "Ska", "Death Metal", "Pranks",
4054 "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal",
4055 "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental",
4056 "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise",
4057 "AlternRock", "Bass", "Soul", "Punk", "Space", "Meditative",
4058 "Instrumental Pop", "Instrumental Rock", "Ethnic", "Gothic",
4059 "Darkwave", "Techno-Industrial", "Electronic", "Pop-Folk",
4060 "Eurodance", "Dream", "Southern Rock", "Comedy", "Cult", "Gangsta",
4061 "Top 40", "Christian Rap", "Pop/Funk", "Jungle", "Native American",
4062 "Cabaret", "New Wave", "Psychadelic", "Rave", "Showtunes",
4063 "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz", "Polka",
4064 "Retro", "Musical", "Rock & Roll", "Hard Rock", "Folk",
4065 "Folk/Rock", "National Folk", "Swing", "Fast-Fusion", "Bebob",
4066 "Latin", "Revival", "Celtic", "Bluegrass", "Avantgarde",
4067 "Gothic Rock", "Progressive Rock", "Psychedelic Rock",
4068 "Symphonic Rock", "Slow Rock", "Big Band", "Chorus",
4069 "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson",
4070 "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass",
4071 "Primus", "Porn Groove", "Satire", "Slow Jam", "Club", "Tango",
4072 "Samba", "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul",
4073 "Freestyle", "Duet", "Punk Rock", "Drum Solo", "A capella",
4074 "Euro-House", "Dance Hall", "Goa", "Drum & Bass", "Club House",
4075 "Hardcore", "Terror", "Indie", "BritPop", "NegerPunk",
4076 "Polsk Punk", "Beat", "Christian Gangsta", "Heavy Metal",
4077 "Black Metal", "Crossover", "Contemporary C", "Christian Rock",
4078 "Merengue", "Salsa", "Thrash Metal", "Anime", "JPop", "SynthPop"
4085 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
4087 len = QT_UINT32 (data->data);
4088 type = QT_UINT32 ((guint8 *) data->data + 8);
4089 if (type == 0x00000000 && len >= 18) {
4090 n = QT_UINT16 ((guint8 *) data->data + 16);
4091 if (n > 0 && n < sizeof (genres) / sizeof (char *)) {
4092 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genres[n]);
4093 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
4094 tag, genres[n], NULL);
4100 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux,
4101 const char *tag, const char *tag_bis, GNode * node);
4106 const gchar *gst_tag;
4107 const gchar *gst_tag_bis;
4108 const GstQTDemuxAddTagFunc func;
4111 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
4112 FOURCC__grp, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
4113 FOURCC__wrt, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
4114 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
4115 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
4116 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
4117 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
4118 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
4119 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
4120 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
4121 FOURCC__too, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
4122 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
4123 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
4124 qtdemux_tag_add_num}, {
4125 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
4126 qtdemux_tag_add_num}, {
4127 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
4128 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
4129 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
4130 FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
4131 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
4132 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}
4136 qtdemux_tag_add_blob (GNode * node, GstQTDemux * demux)
4141 gchar *media_type, *style;
4145 len = QT_UINT32 (data);
4146 buf = gst_buffer_new_and_alloc (len);
4147 memcpy (GST_BUFFER_DATA (buf), data, len);
4149 /* heuristic to determine style of tag */
4150 if (QT_FOURCC (data + 4) == FOURCC_____ ||
4151 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
4153 else if (demux->major_brand == GST_MAKE_FOURCC ('q', 't', ' ', ' '))
4154 style = "quicktime";
4155 /* fall back to assuming iso/3gp tag style */
4159 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
4160 g_ascii_tolower (data[4]), g_ascii_tolower (data[5]),
4161 g_ascii_tolower (data[6]), g_ascii_tolower (data[7]));
4162 caps = gst_caps_new_simple (media_type, "style", G_TYPE_STRING, style, NULL);
4163 gst_buffer_set_caps (buf, caps);
4164 gst_caps_unref (caps);
4165 g_free (media_type);
4167 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, caps %" GST_PTR_FORMAT,
4168 GST_BUFFER_SIZE (buf), caps);
4170 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_APPEND,
4171 GST_QT_DEMUX_PRIVATE_TAG, buf, NULL);
4172 gst_buffer_unref (buf);
4176 qtdemux_parse_udta (GstQTDemux * qtdemux, GNode * udta)
4183 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
4185 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
4187 GST_LOG_OBJECT (qtdemux, "no ilst");
4192 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
4195 GST_DEBUG_OBJECT (qtdemux, "new tag list");
4196 qtdemux->tag_list = gst_tag_list_new ();
4198 for (i = 0; i < G_N_ELEMENTS (add_funcs); ++i) {
4199 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
4201 add_funcs[i].func (qtdemux, add_funcs[i].gst_tag,
4202 add_funcs[i].gst_tag_bis, node);
4203 g_node_destroy (node);
4207 /* parsed nodes have been removed, pass along remainder as blob */
4208 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
4209 (GNodeForeachFunc) qtdemux_tag_add_blob, qtdemux);
4215 GstStructure *structure; /* helper for sort function */
4217 guint min_req_bitrate;
4218 guint min_req_qt_version;
4222 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
4224 GstQtReference *ref_a = (GstQtReference *) a;
4225 GstQtReference *ref_b = (GstQtReference *) b;
4227 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
4228 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
4230 /* known bitrates go before unknown; higher bitrates go first */
4231 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
4234 /* sort the redirects and post a message for the application.
4237 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
4239 GstQtReference *best;
4242 GValue list_val = { 0, };
4245 g_assert (references != NULL);
4247 references = g_list_sort (references, qtdemux_redirects_sort_func);
4249 best = (GstQtReference *) references->data;
4251 g_value_init (&list_val, GST_TYPE_LIST);
4253 for (l = references; l != NULL; l = l->next) {
4254 GstQtReference *ref = (GstQtReference *) l->data;
4255 GValue struct_val = { 0, };
4257 ref->structure = gst_structure_new ("redirect",
4258 "new-location", G_TYPE_STRING, ref->location, NULL);
4260 if (ref->min_req_bitrate > 0) {
4261 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
4262 ref->min_req_bitrate, NULL);
4265 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
4266 g_value_set_boxed (&struct_val, ref->structure);
4267 gst_value_list_append_value (&list_val, &struct_val);
4268 g_value_unset (&struct_val);
4269 /* don't free anything here yet, since we need best->structure below */
4272 g_assert (best != NULL);
4273 s = gst_structure_copy (best->structure);
4275 if (g_list_length (references) > 1) {
4276 gst_structure_set_value (s, "locations", &list_val);
4279 g_value_unset (&list_val);
4281 for (l = references; l != NULL; l = l->next) {
4282 GstQtReference *ref = (GstQtReference *) l->data;
4284 gst_structure_free (ref->structure);
4285 g_free (ref->location);
4288 g_list_free (references);
4290 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
4291 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
4292 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
4295 /* look for redirect nodes, collect all redirect information and
4299 qtdemux_parse_redirects (GstQTDemux * qtdemux)
4301 GNode *rmra, *rmda, *rdrf;
4303 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
4305 GList *redirects = NULL;
4307 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
4309 GstQtReference ref = { NULL, NULL, 0, 0 };
4312 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
4313 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
4314 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
4315 ref.min_req_bitrate);
4318 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
4319 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
4320 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
4322 #ifndef GST_DISABLE_GST_DEBUG
4323 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
4325 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
4327 GST_LOG_OBJECT (qtdemux,
4328 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
4329 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
4330 bitmask, check_type);
4331 if (package == FOURCC_qtim && check_type == 0) {
4332 ref.min_req_qt_version = version;
4336 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
4341 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
4342 ref_data = (guint8 *) rdrf->data + 20;
4343 if (ref_type == FOURCC_alis) {
4344 guint record_len, record_version, fn_len;
4346 /* MacOSX alias record, google for alias-layout.txt */
4347 record_len = QT_UINT16 (ref_data + 4);
4348 record_version = QT_UINT16 (ref_data + 4 + 2);
4349 fn_len = QT_UINT8 (ref_data + 50);
4350 if (record_len > 50 && record_version == 2 && fn_len > 0) {
4351 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
4353 } else if (ref_type == FOURCC_url_) {
4354 ref.location = g_strdup ((gchar *) ref_data);
4356 GST_DEBUG_OBJECT (qtdemux,
4357 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
4358 GST_FOURCC_ARGS (ref_type));
4360 if (ref.location != NULL) {
4361 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
4362 redirects = g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
4364 GST_WARNING_OBJECT (qtdemux,
4365 "Failed to extract redirect location from rdrf atom");
4369 /* look for others */
4370 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
4373 if (redirects != NULL) {
4374 qtdemux_process_redirects (qtdemux, redirects);
4380 /* we have read th complete moov node now.
4381 * This function parses all of the relevant info, creates the traks and
4382 * prepares all data structures for playback
4385 qtdemux_parse_tree (GstQTDemux * qtdemux)
4392 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
4394 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
4395 return qtdemux_parse_redirects (qtdemux);
4398 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
4399 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
4401 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
4402 GST_INFO_OBJECT (qtdemux, "duration: %u", qtdemux->duration);
4404 /* set duration in the segment info */
4405 gst_qtdemux_get_duration (qtdemux, &duration);
4406 gst_segment_set_duration (&qtdemux->segment, GST_FORMAT_TIME, duration);
4408 /* parse all traks */
4409 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
4411 qtdemux_parse_trak (qtdemux, trak);
4412 /* iterate all siblings */
4413 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
4415 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
4417 /* find and push tags, we do this after adding the pads so we can push the
4418 * tags downstream as well. */
4419 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
4421 qtdemux_parse_udta (qtdemux, udta);
4423 if (qtdemux->tag_list) {
4424 GST_DEBUG_OBJECT (qtdemux,
4425 "calling gst_element_found_tags with %" GST_PTR_FORMAT,
4427 gst_element_found_tags (GST_ELEMENT_CAST (qtdemux), qtdemux->tag_list);
4428 qtdemux->tag_list = NULL;
4431 GST_LOG_OBJECT (qtdemux, "No udta node found.");
4436 /* taken from ffmpeg */
4438 get_size (guint8 * ptr, guint8 ** end)
4447 len = (len << 7) | (c & 0x7f);
4456 /* this can change the codec originally present in @list */
4458 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
4459 GNode * esds, GstTagList * list)
4461 int len = QT_UINT32 (esds->data);
4462 guint8 *ptr = esds->data;
4463 guint8 *end = ptr + len;
4465 guint8 *data_ptr = NULL;
4467 guint8 object_type_id = 0;
4469 qtdemux_dump_mem (ptr, len);
4471 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
4474 tag = QT_UINT8 (ptr);
4475 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
4477 len = get_size (ptr, &ptr);
4478 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
4482 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
4483 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
4487 object_type_id = QT_UINT8 (ptr);
4488 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
4489 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
4490 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
4491 GST_DEBUG_OBJECT (qtdemux, "max bitrate %d", QT_UINT32 (ptr + 5));
4492 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %d", QT_UINT32 (ptr + 9));
4496 GST_DEBUG_OBJECT (qtdemux, "data:");
4497 qtdemux_dump_mem (ptr, len);
4503 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
4507 GST_ERROR_OBJECT (qtdemux, "parse error");
4514 buffer = gst_buffer_new_and_alloc (data_len);
4515 memcpy (GST_BUFFER_DATA (buffer), data_ptr, data_len);
4516 qtdemux_dump_mem (GST_BUFFER_DATA (buffer), data_len);
4518 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
4520 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
4522 gst_buffer_unref (buffer);
4524 /* object_type_id in the stsd atom in mp4a tells us about AAC or plain
4525 * MPEG audio and other formats */
4526 switch (object_type_id) {
4528 /* change to mpeg1 layer 3 audio */
4529 gst_caps_set_simple (stream->caps, "layer", G_TYPE_INT, 3,
4530 "mpegversion", G_TYPE_INT, 1, NULL);
4532 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
4533 GST_TAG_AUDIO_CODEC, "MPEG-1 layer 3", NULL);
4537 GstStructure *structure;
4539 /* QCELP, the codec_data is a riff tag (little endian) with
4540 * 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). */
4541 structure = gst_caps_get_structure (stream->caps, 0);
4542 gst_structure_set_name (structure, "audio/qcelp");
4543 gst_structure_remove_fields (structure, "mpegversion", "framed", NULL);
4546 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
4547 GST_TAG_AUDIO_CODEC, "QCELP", NULL);
4555 #define _codec(name) \
4558 *codec_name = g_strdup (name); \
4563 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
4564 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
4567 const GstStructure *s;
4571 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
4572 _codec ("PNG still images");
4573 caps = gst_caps_new_simple ("image/png", NULL);
4575 case GST_MAKE_FOURCC ('j', 'p', 'e', 'g'):
4576 _codec ("JPEG still images");
4577 caps = gst_caps_new_simple ("image/jpeg", NULL);
4579 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
4580 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
4581 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
4582 _codec ("Motion-JPEG");
4583 caps = gst_caps_new_simple ("image/jpeg", NULL);
4585 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
4586 _codec ("Motion-JPEG format B");
4587 caps = gst_caps_new_simple ("video/x-mjpeg-b", NULL);
4589 case GST_MAKE_FOURCC ('m', 'j', 'p', '2'):
4590 _codec ("JPEG-2000");
4591 /* override to what it should be according to spec, avoid palette_data */
4592 stream->bits_per_sample = 24;
4593 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
4595 case GST_MAKE_FOURCC ('S', 'V', 'Q', '3'):
4596 _codec ("Sorensen video v.3");
4597 caps = gst_caps_new_simple ("video/x-svq",
4598 "svqversion", G_TYPE_INT, 3, NULL);
4600 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
4601 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
4602 _codec ("Sorensen video v.1");
4603 caps = gst_caps_new_simple ("video/x-svq",
4604 "svqversion", G_TYPE_INT, 1, NULL);
4606 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
4610 _codec ("Raw RGB video");
4611 bps = QT_UINT16 (stsd_data + 98);
4612 /* set common stuff */
4613 caps = gst_caps_new_simple ("video/x-raw-rgb",
4614 "endianness", G_TYPE_INT, G_BYTE_ORDER, "depth", G_TYPE_INT, bps,
4619 gst_caps_set_simple (caps,
4620 "bpp", G_TYPE_INT, 16,
4621 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
4622 "red_mask", G_TYPE_INT, 0x7c00,
4623 "green_mask", G_TYPE_INT, 0x03e0,
4624 "blue_mask", G_TYPE_INT, 0x001f, NULL);
4627 gst_caps_set_simple (caps,
4628 "bpp", G_TYPE_INT, 16,
4629 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
4630 "red_mask", G_TYPE_INT, 0xf800,
4631 "green_mask", G_TYPE_INT, 0x07e0,
4632 "blue_mask", G_TYPE_INT, 0x001f, NULL);
4635 gst_caps_set_simple (caps,
4636 "bpp", G_TYPE_INT, 24,
4637 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
4638 "red_mask", G_TYPE_INT, 0xff0000,
4639 "green_mask", G_TYPE_INT, 0x00ff00,
4640 "blue_mask", G_TYPE_INT, 0x0000ff, NULL);
4643 gst_caps_set_simple (caps,
4644 "bpp", G_TYPE_INT, 32,
4645 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
4646 "alpha_mask", G_TYPE_INT, 0xff000000,
4647 "red_mask", G_TYPE_INT, 0x00ff0000,
4648 "green_mask", G_TYPE_INT, 0x0000ff00,
4649 "blue_mask", G_TYPE_INT, 0x000000ff, NULL);
4657 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
4658 _codec ("Raw planar YUV 4:2:0");
4659 caps = gst_caps_new_simple ("video/x-raw-yuv",
4660 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I', '4', '2', '0'),
4663 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
4664 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
4665 _codec ("Raw packed YUV 4:2:2");
4666 caps = gst_caps_new_simple ("video/x-raw-yuv",
4667 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'),
4670 case GST_MAKE_FOURCC ('2', 'v', 'u', 'y'):
4671 _codec ("Raw packed YUV 4:2:0");
4672 caps = gst_caps_new_simple ("video/x-raw-yuv",
4673 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'),
4676 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
4677 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
4678 _codec ("MPEG-1 video");
4679 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
4680 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
4682 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): // HDV 720p30
4683 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): // HDV 1080i60
4684 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): // HDV 1080i50
4685 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): // HDV 720p25
4686 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): // HDV 1080i60
4687 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): // MPEG2 IMX NTSC 525/60 50mb/s produced by FCP
4688 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): // MPEG2 IMX PAL 625/60 50mb/s produced by FCP
4689 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): // MPEG2 IMX NTSC 525/60 40mb/s produced by FCP
4690 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): // MPEG2 IMX PAL 625/60 40mb/s produced by FCP
4691 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): // MPEG2 IMX NTSC 525/60 30mb/s produced by FCP
4692 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): // MPEG2 IMX PAL 625/50 30mb/s produced by FCP
4693 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): // XDCAM HD 1080i60
4694 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): // AVID IMX PAL
4695 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): // AVID IMX PAL
4696 _codec ("MPEG-2 video");
4697 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
4698 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
4700 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
4701 _codec ("GIF still images");
4702 caps = gst_caps_new_simple ("image/gif", NULL);
4704 case GST_MAKE_FOURCC ('h', '2', '6', '3'):
4705 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
4706 case GST_MAKE_FOURCC ('s', '2', '6', '3'):
4707 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
4709 /* ffmpeg uses the height/width props, don't know why */
4710 caps = gst_caps_new_simple ("video/x-h263", NULL);
4712 case GST_MAKE_FOURCC ('m', 'p', '4', 'v'):
4713 _codec ("MPEG-4 video");
4714 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
4715 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
4717 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
4718 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
4719 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
4720 caps = gst_caps_new_simple ("video/x-msmpeg",
4721 "msmpegversion", G_TYPE_INT, 43, NULL);
4723 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
4724 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
4725 _codec ("3ivX video");
4726 caps = gst_caps_new_simple ("video/x-3ivx", NULL);
4728 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
4730 caps = gst_caps_new_simple ("video/x-divx",
4731 "divxversion", G_TYPE_INT, 3, NULL);
4733 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
4734 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
4736 caps = gst_caps_new_simple ("video/x-divx",
4737 "divxversion", G_TYPE_INT, 4, NULL);
4739 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
4741 caps = gst_caps_new_simple ("video/x-divx",
4742 "divxversion", G_TYPE_INT, 5, NULL);
4744 case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
4745 case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
4746 _codec ("XVID MPEG-4");
4747 caps = gst_caps_new_simple ("video/x-xvid", NULL);
4750 case GST_MAKE_FOURCC ('F', 'M', 'P', '4'):
4751 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
4752 caps = gst_caps_new_simple ("video/mpeg",
4753 "mpegversion", G_TYPE_INT, 4, NULL);
4755 *codec_name = g_strdup ("FFmpeg MPEG-4");
4758 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
4760 caps = gst_caps_new_simple ("video/x-cinepak", NULL);
4762 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
4763 _codec ("Apple QuickDraw");
4764 caps = gst_caps_new_simple ("video/x-qdrw", NULL);
4766 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
4767 _codec ("Apple video");
4768 caps = gst_caps_new_simple ("video/x-apple-video", NULL);
4770 case GST_MAKE_FOURCC ('a', 'v', 'c', '1'):
4771 _codec ("H.264 / AVC");
4772 caps = gst_caps_new_simple ("video/x-h264", NULL);
4774 case GST_MAKE_FOURCC ('r', 'l', 'e', ' '):
4775 _codec ("Run-length encoding");
4776 caps = gst_caps_new_simple ("video/x-rle",
4777 "layout", G_TYPE_STRING, "quicktime", NULL);
4779 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
4780 _codec ("Indeo Video 3");
4781 caps = gst_caps_new_simple ("video/x-indeo",
4782 "indeoversion", G_TYPE_INT, 3, NULL);
4784 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
4785 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
4786 _codec ("Intel Video 4");
4787 caps = gst_caps_new_simple ("video/x-indeo",
4788 "indeoversion", G_TYPE_INT, 4, NULL);
4790 case GST_MAKE_FOURCC ('d', 'v', 'c', 'p'):
4791 case GST_MAKE_FOURCC ('d', 'v', 'c', ' '):
4792 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
4793 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
4794 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
4795 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
4796 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
4797 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
4798 _codec ("DV Video");
4799 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
4800 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
4802 case GST_MAKE_FOURCC ('d', 'v', '5', 'n'): //DVCPRO50 NTSC
4803 case GST_MAKE_FOURCC ('d', 'v', '5', 'p'): //DVCPRO50 PAL
4804 _codec ("DVCPro50 Video");
4805 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
4806 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
4808 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): //DVCPRO HD 50i produced by FCP
4809 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): //DVCPRO HD 60i produced by FCP
4810 _codec ("DVCProHD Video");
4811 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
4812 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
4814 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
4815 _codec ("Apple Graphics (SMC)");
4816 caps = gst_caps_new_simple ("video/x-smc", NULL);
4818 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
4820 caps = gst_caps_new_simple ("video/x-vp3", NULL);
4822 case GST_MAKE_FOURCC ('X', 'i', 'T', 'h'):
4824 caps = gst_caps_new_simple ("video/x-theora", NULL);
4825 /* theora uses one byte of padding in the data stream because it does not
4826 * allow 0 sized packets while theora does */
4827 stream->padding = 1;
4829 case GST_MAKE_FOURCC ('d', 'r', 'a', 'c'):
4831 caps = gst_caps_new_simple ("video/x-dirac", NULL);
4833 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
4834 _codec ("TIFF still images");
4835 caps = gst_caps_new_simple ("image/tiff", NULL);
4837 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
4842 s = g_strdup_printf ("video/x-gst-fourcc-%" GST_FOURCC_FORMAT,
4843 GST_FOURCC_ARGS (fourcc));
4844 caps = gst_caps_new_simple (s, NULL);
4849 /* enable clipping for raw video streams */
4850 s = gst_caps_get_structure (caps, 0);
4851 name = gst_structure_get_name (s);
4852 if (g_str_has_prefix (name, "video/x-raw-")) {
4853 stream->need_clip = TRUE;
4859 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
4860 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
4863 const GstStructure *s;
4867 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
4870 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
4871 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
4872 _codec ("Raw 8-bit PCM audio");
4873 caps = gst_caps_new_simple ("audio/x-raw-int", "width", G_TYPE_INT, 8,
4874 "depth", G_TYPE_INT, 8, "signed", G_TYPE_BOOLEAN, FALSE, NULL);
4876 case GST_MAKE_FOURCC ('t', 'w', 'o', 's'):
4877 endian = G_BIG_ENDIAN;
4879 case GST_MAKE_FOURCC ('s', 'o', 'w', 't'):
4885 endian = G_LITTLE_ENDIAN;
4887 depth = stream->bytes_per_packet * 8;
4888 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
4891 caps = gst_caps_new_simple ("audio/x-raw-int",
4892 "width", G_TYPE_INT, depth, "depth", G_TYPE_INT, depth,
4893 "endianness", G_TYPE_INT, endian,
4894 "signed", G_TYPE_BOOLEAN, TRUE, NULL);
4897 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
4898 _codec ("Raw 64-bit floating-point audio");
4899 caps = gst_caps_new_simple ("audio/x-raw-float", "width", G_TYPE_INT, 64,
4900 "endianness", G_TYPE_INT, G_BIG_ENDIAN, NULL);
4902 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
4903 _codec ("Raw 32-bit floating-point audio");
4904 caps = gst_caps_new_simple ("audio/x-raw-float", "width", G_TYPE_INT, 32,
4905 "endianness", G_TYPE_INT, G_BIG_ENDIAN, NULL);
4907 case GST_MAKE_FOURCC ('i', 'n', '2', '4'):
4908 _codec ("Raw 24-bit PCM audio");
4909 caps = gst_caps_new_simple ("audio/x-raw-int", "width", G_TYPE_INT, 24,
4910 "depth", G_TYPE_INT, 24,
4911 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
4912 "signed", G_TYPE_BOOLEAN, TRUE, NULL);
4914 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
4915 _codec ("Raw 32-bit PCM audio");
4916 caps = gst_caps_new_simple ("audio/x-raw-int", "width", G_TYPE_INT, 32,
4917 "depth", G_TYPE_INT, 32,
4918 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
4919 "signed", G_TYPE_BOOLEAN, TRUE, NULL);
4921 case GST_MAKE_FOURCC ('u', 'l', 'a', 'w'):
4922 _codec ("Mu-law audio");
4923 caps = gst_caps_new_simple ("audio/x-mulaw", NULL);
4925 case GST_MAKE_FOURCC ('a', 'l', 'a', 'w'):
4926 _codec ("A-law audio");
4927 caps = gst_caps_new_simple ("audio/x-alaw", NULL);
4931 _codec ("Microsoft ADPCM");
4932 /* Microsoft ADPCM-ACM code 2 */
4933 caps = gst_caps_new_simple ("audio/x-adpcm",
4934 "layout", G_TYPE_STRING, "microsoft", NULL);
4938 _codec ("IMA Loki SDL MJPEG ADPCM");
4939 /* Loki ADPCM, See #550288 for a file that only decodes
4940 * with the smjpeg variant of the ADPCM decoder. */
4941 caps = gst_caps_new_simple ("audio/x-adpcm",
4942 "layout", G_TYPE_STRING, "smjpeg", NULL);
4946 _codec ("DVI/Intel IMA ADPCM");
4947 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
4948 caps = gst_caps_new_simple ("audio/x-adpcm",
4949 "layout", G_TYPE_STRING, "quicktime", NULL);
4953 /* MPEG layer 3, CBR only (pre QT4.1) */
4954 case GST_MAKE_FOURCC ('.', 'm', 'p', '3'):
4955 _codec ("MPEG-1 layer 3");
4956 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
4957 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
4958 "mpegversion", G_TYPE_INT, 1, NULL);
4961 _codec ("AC-3 audio");
4962 caps = gst_caps_new_simple ("audio/x-ac3", NULL);
4964 case GST_MAKE_FOURCC ('M', 'A', 'C', '3'):
4966 caps = gst_caps_new_simple ("audio/x-mace",
4967 "maceversion", G_TYPE_INT, 3, NULL);
4969 case GST_MAKE_FOURCC ('M', 'A', 'C', '6'):
4971 caps = gst_caps_new_simple ("audio/x-mace",
4972 "maceversion", G_TYPE_INT, 6, NULL);
4974 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
4976 caps = gst_caps_new_simple ("application/ogg", NULL);
4978 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
4979 _codec ("DV audio");
4980 caps = gst_caps_new_simple ("audio/x-dv", NULL);
4982 case GST_MAKE_FOURCC ('m', 'p', '4', 'a'):
4983 _codec ("MPEG-4 AAC audio");
4984 caps = gst_caps_new_simple ("audio/mpeg",
4985 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE, NULL);
4987 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
4988 _codec ("QDesign Music");
4989 caps = gst_caps_new_simple ("audio/x-qdm", NULL);
4991 case GST_MAKE_FOURCC ('Q', 'D', 'M', '2'):
4992 _codec ("QDesign Music v.2");
4993 /* FIXME: QDesign music version 2 (no constant) */
4995 caps = gst_caps_new_simple ("audio/x-qdm2",
4996 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
4997 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
4998 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
5000 caps = gst_caps_new_simple ("audio/x-qdm2", NULL);
5003 case GST_MAKE_FOURCC ('a', 'g', 's', 'm'):
5004 _codec ("GSM audio");
5005 caps = gst_caps_new_simple ("audio/x-gsm", NULL);
5007 case GST_MAKE_FOURCC ('s', 'a', 'm', 'r'):
5008 _codec ("AMR audio");
5009 caps = gst_caps_new_simple ("audio/AMR", NULL);
5011 case GST_MAKE_FOURCC ('s', 'a', 'w', 'b'):
5012 _codec ("AMR-WB audio");
5013 caps = gst_caps_new_simple ("audio/AMR-WB", NULL);
5015 case GST_MAKE_FOURCC ('i', 'm', 'a', '4'):
5016 _codec ("Quicktime IMA ADPCM");
5017 caps = gst_caps_new_simple ("audio/x-adpcm",
5018 "layout", G_TYPE_STRING, "quicktime", NULL);
5020 case GST_MAKE_FOURCC ('a', 'l', 'a', 'c'):
5021 _codec ("Apple lossless audio");
5022 caps = gst_caps_new_simple ("audio/x-alac", NULL);
5024 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
5026 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
5027 /* QUALCOMM PureVoice */
5032 s = g_strdup_printf ("audio/x-gst-fourcc-%" GST_FOURCC_FORMAT,
5033 GST_FOURCC_ARGS (fourcc));
5034 caps = gst_caps_new_simple (s, NULL);
5039 /* enable clipping for raw audio streams */
5040 s = gst_caps_get_structure (caps, 0);
5041 name = gst_structure_get_name (s);
5042 if (g_str_has_prefix (name, "audio/x-raw-")) {
5043 stream->need_clip = TRUE;