2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) <2003> David A. Schleef <ds@schleef.org>
4 * Copyright (C) <2006> Wim Taymans <wim@fluendo.com>
5 * Copyright (C) <2007> Julien Moutte <julien@fluendo.com>
6 * Copyright (C) <2009> Tim-Philipp Müller <tim centricular net>
7 * Copyright (C) <2009> STEricsson <benjamin.gaignard@stericsson.com>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the
21 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 * Boston, MA 02111-1307, USA.
26 * SECTION:element-qtdemux
28 * Demuxes a .mov file into raw or compressed audio and/or video streams.
30 * This element supports both push and pull-based scheduling, depending on the
31 * capabilities of the upstream elements.
34 * <title>Example launch line</title>
36 * gst-launch filesrc location=test.mov ! qtdemux name=demux demux.audio_0 ! decodebin ! audioconvert ! audioresample ! autoaudiosink demux.video_0 ! queue ! decodebin ! ffmpegcolorspace ! videoscale ! autovideosink
37 * ]| Play (parse and decode) a .mov file and try to output it to
38 * an automatically detected soundcard and videosink. If the MOV file contains
39 * compressed audio or video data, this will only work if you have the
40 * right decoder elements/plugins installed.
43 * Last reviewed on 2006-12-29 (0.10.5)
50 #include "gst/gst-i18n-plugin.h"
52 #include <glib/gprintf.h>
53 #include <gst/tag/tag.h>
54 #include <gst/audio/audio.h>
56 #include "qtatomparser.h"
57 #include "qtdemux_types.h"
58 #include "qtdemux_dump.h"
59 #include "qtdemux_fourcc.h"
60 #include "qtdemux_lang.h"
62 #include "qtpalette.h"
64 #include "gst/riff/riff-media.h"
65 #include "gst/riff/riff-read.h"
67 #include <gst/pbutils/pbutils.h>
77 /* max. size considered 'sane' for non-mdat atoms */
78 #define QTDEMUX_MAX_ATOM_SIZE (25*1024*1024)
80 /* if the sample index is larger than this, something is likely wrong */
81 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (50*1024*1024)
83 /* For converting qt creation times to unix epoch times */
84 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
85 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
86 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
87 QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
89 GST_DEBUG_CATEGORY (qtdemux_debug);
91 /*typedef struct _QtNode QtNode; */
92 typedef struct _QtDemuxSegment QtDemuxSegment;
93 typedef struct _QtDemuxSample QtDemuxSample;
102 struct _QtDemuxSample
105 gint32 pts_offset; /* Add this value to timestamp to get the pts */
107 guint64 timestamp; /* DTS In mov time */
108 guint32 duration; /* In mov time */
109 gboolean keyframe; /* TRUE when this packet is a keyframe */
112 /* timestamp is the DTS */
113 #define QTSAMPLE_DTS(stream,sample) gst_util_uint64_scale ((sample)->timestamp,\
114 GST_SECOND, (stream)->timescale)
115 /* timestamp + offset is the PTS */
116 #define QTSAMPLE_PTS(stream,sample) gst_util_uint64_scale ((sample)->timestamp + \
117 (sample)->pts_offset, GST_SECOND, (stream)->timescale)
118 /* timestamp + duration - dts is the duration */
119 #define QTSAMPLE_DUR_DTS(stream,sample,dts) (gst_util_uint64_scale ((sample)->timestamp + \
120 (sample)->duration, GST_SECOND, (stream)->timescale) - (dts));
122 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
125 * Quicktime has tracks and segments. A track is a continuous piece of
126 * multimedia content. The track is not always played from start to finish but
127 * instead, pieces of the track are 'cut out' and played in sequence. This is
128 * what the segments do.
130 * Inside the track we have keyframes (K) and delta frames. The track has its
131 * own timing, which starts from 0 and extends to end. The position in the track
132 * is called the media_time.
134 * The segments now describe the pieces that should be played from this track
135 * and are basically tupples of media_time/duration/rate entries. We can have
136 * multiple segments and they are all played after one another. An example:
138 * segment 1: media_time: 1 second, duration: 1 second, rate 1
139 * segment 2: media_time: 3 second, duration: 2 second, rate 2
141 * To correctly play back this track, one must play: 1 second of media starting
142 * from media_time 1 followed by 2 seconds of media starting from media_time 3
145 * Each of the segments will be played at a specific time, the first segment at
146 * time 0, the second one after the duration of the first one, etc.. Note that
147 * the time in resulting playback is not identical to the media_time of the
150 * Visually, assuming the track has 4 second of media_time:
153 * .-----------------------------------------------------------.
154 * track: | K.....K.........K........K.......K.......K...........K... |
155 * '-----------------------------------------------------------'
157 * .------------^ ^ .----------^ ^
158 * / .-------------' / .------------------'
160 * .--------------. .--------------.
161 * | segment 1 | | segment 2 |
162 * '--------------' '--------------'
164 * The challenge here is to cut out the right pieces of the track for each of
165 * the playback segments. This fortunatly can easily be done with the SEGMENT
166 * events of gstreamer.
168 * For playback of segment 1, we need to provide the decoder with the keyframe
169 * (a), in the above figure, but we must instruct it only to output the decoded
170 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
171 * position set to the time of the segment: 0.
173 * We then proceed to push data from keyframe (a) to frame (b). The decoder
174 * decodes but clips all before media_time 1.
176 * After finishing a segment, we push out a new SEGMENT event with the clipping
177 * boundaries of the new data.
179 * This is a good usecase for the GStreamer accumulated SEGMENT events.
182 struct _QtDemuxSegment
184 /* global time and duration, all gst time */
188 /* media time of trak, all gst time */
194 struct _QtDemuxStream
203 /* if the stream has a redirect URI in its headers, we store it here */
210 guint64 duration; /* in timescale */
214 gchar lang_id[4]; /* ISO 639-2T language code */
218 QtDemuxSample *samples;
219 gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */
220 guint32 min_duration; /* duration in timescale of first sample, used for figuring out
221 the framerate, in timescale units */
223 /* if we use chunks or samples */
235 /* Numerator/denominator framerate */
238 guint16 bits_per_sample;
239 guint16 color_table_id;
244 guint samples_per_packet;
245 guint samples_per_frame;
246 guint bytes_per_packet;
247 guint bytes_per_sample;
248 guint bytes_per_frame;
251 /* when a discontinuity is pending */
254 /* list of buffers to push first */
257 /* if we need to clip this buffer. This is only needed for uncompressed
261 /* buffer needs some custom processing, e.g. subtitles */
262 gboolean need_process;
264 /* current position */
265 guint32 segment_index;
266 guint32 sample_index;
267 guint64 time_position; /* in gst time */
269 /* the Gst segment we are processing out, used for clipping */
272 /* last GstFlowReturn */
273 GstFlowReturn last_ret;
275 /* quicktime segments */
277 QtDemuxSegment *segments;
282 GstTagList *pending_tags;
283 gboolean send_global_tags;
285 GstEvent *pending_event;
295 gboolean chunks_are_chunks;
299 GstByteReader co_chunk;
301 guint32 current_chunk;
303 guint32 samples_per_chunk;
304 guint32 stco_sample_index;
306 guint32 sample_size; /* 0 means variable sizes are stored in stsz */
309 guint32 n_samples_per_chunk;
310 guint32 stsc_chunk_index;
311 guint32 stsc_sample_index;
312 guint64 chunk_offset;
315 guint32 stts_samples;
316 guint32 n_sample_times;
317 guint32 stts_sample_index;
319 guint32 stts_duration;
321 gboolean stss_present;
322 guint32 n_sample_syncs;
325 gboolean stps_present;
326 guint32 n_sample_partial_syncs;
329 gboolean ctts_present;
330 guint32 n_composition_times;
332 guint32 ctts_sample_index;
337 gboolean parsed_trex;
338 guint32 def_sample_duration;
339 guint32 def_sample_size;
340 guint32 def_sample_flags;
345 QTDEMUX_STATE_INITIAL, /* Initial state (haven't got the header yet) */
346 QTDEMUX_STATE_HEADER, /* Parsing the header */
347 QTDEMUX_STATE_MOVIE, /* Parsing/Playing the media data */
348 QTDEMUX_STATE_BUFFER_MDAT /* Buffering the mdat atom */
351 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
352 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
353 guint32 fourcc, GstByteReader * parser);
354 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
355 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
356 guint32 fourcc, GstByteReader * parser);
358 static GstStaticPadTemplate gst_qtdemux_sink_template =
359 GST_STATIC_PAD_TEMPLATE ("sink",
362 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
366 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
367 GST_STATIC_PAD_TEMPLATE ("video_%u",
370 GST_STATIC_CAPS_ANY);
372 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
373 GST_STATIC_PAD_TEMPLATE ("audio_%u",
376 GST_STATIC_CAPS_ANY);
378 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
379 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
382 GST_STATIC_CAPS_ANY);
384 #define gst_qtdemux_parent_class parent_class
385 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
387 static void gst_qtdemux_dispose (GObject * object);
390 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
393 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
394 QtDemuxStream * str, gint64 media_offset);
397 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
398 static GstIndex *gst_qtdemux_get_index (GstElement * element);
400 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
401 GstStateChange transition);
402 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
403 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
404 GstObject * parent, GstPadMode mode, gboolean active);
406 static void gst_qtdemux_loop (GstPad * pad);
407 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
409 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
412 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
413 const guint8 * buffer, guint length);
414 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
415 const guint8 * buffer, guint length);
416 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
418 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
419 QtDemuxStream * stream, GNode * esds, GstTagList * list);
420 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
421 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
422 gchar ** codec_name);
423 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
424 QtDemuxStream * stream, guint32 fourcc, const guint8 * data, int len,
425 gchar ** codec_name);
426 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux,
427 QtDemuxStream * stream, guint32 fourcc, const guint8 * data,
428 gchar ** codec_name);
429 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
430 QtDemuxStream * stream, guint32 n);
431 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
434 gst_qtdemux_class_init (GstQTDemuxClass * klass)
436 GObjectClass *gobject_class;
437 GstElementClass *gstelement_class;
439 gobject_class = (GObjectClass *) klass;
440 gstelement_class = (GstElementClass *) klass;
442 parent_class = g_type_class_peek_parent (klass);
444 gobject_class->dispose = gst_qtdemux_dispose;
446 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
448 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
449 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
452 gst_tag_register_musicbrainz_tags ();
454 gst_element_class_add_pad_template (gstelement_class,
455 gst_static_pad_template_get (&gst_qtdemux_sink_template));
456 gst_element_class_add_pad_template (gstelement_class,
457 gst_static_pad_template_get (&gst_qtdemux_videosrc_template));
458 gst_element_class_add_pad_template (gstelement_class,
459 gst_static_pad_template_get (&gst_qtdemux_audiosrc_template));
460 gst_element_class_add_pad_template (gstelement_class,
461 gst_static_pad_template_get (&gst_qtdemux_subsrc_template));
462 gst_element_class_set_details_simple (gstelement_class, "QuickTime demuxer",
464 "Demultiplex a QuickTime file into audio and video streams",
465 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
467 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
472 gst_qtdemux_init (GstQTDemux * qtdemux)
475 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
476 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
477 gst_pad_set_activatemode_function (qtdemux->sinkpad,
478 qtdemux_sink_activate_mode);
479 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
480 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
481 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
483 qtdemux->state = QTDEMUX_STATE_INITIAL;
484 qtdemux->pullbased = FALSE;
485 qtdemux->posted_redirect = FALSE;
486 qtdemux->neededbytes = 16;
488 qtdemux->adapter = gst_adapter_new ();
490 qtdemux->first_mdat = -1;
491 qtdemux->got_moov = FALSE;
492 qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
493 qtdemux->mdatbuffer = NULL;
494 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
496 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
500 gst_qtdemux_dispose (GObject * object)
502 GstQTDemux *qtdemux = GST_QTDEMUX (object);
504 if (qtdemux->adapter) {
505 g_object_unref (G_OBJECT (qtdemux->adapter));
506 qtdemux->adapter = NULL;
509 G_OBJECT_CLASS (parent_class)->dispose (object);
513 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
515 if (qtdemux->posted_redirect) {
516 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
517 (_("This file contains no playable streams.")),
518 ("no known streams found, a redirect message has been posted"));
520 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
521 (_("This file contains no playable streams.")),
522 ("no known streams found"));
527 _gst_buffer_copy_into_mem (GstBuffer * dest, gsize offset, const guint8 * src,
532 g_return_if_fail (gst_buffer_is_writable (dest));
534 bsize = gst_buffer_get_size (dest);
535 g_return_if_fail (bsize >= offset + size);
537 gst_buffer_fill (dest, offset, src, size);
541 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
545 buf = gst_buffer_new ();
546 gst_buffer_take_memory (buf, -1,
547 gst_memory_new_wrapped (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
548 mem, size, 0, size, mem, free_func));
554 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
561 if (G_UNLIKELY (size == 0)) {
563 GstBuffer *tmp = NULL;
565 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
566 if (ret != GST_FLOW_OK)
569 gst_buffer_map (tmp, &map, GST_MAP_READ);
570 size = QT_UINT32 (map.data);
571 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
573 gst_buffer_unmap (tmp, &map);
574 gst_buffer_unref (tmp);
577 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
578 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
579 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
580 /* we're pulling header but already got most interesting bits,
581 * so never mind the rest (e.g. tags) (that much) */
582 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
586 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
587 (_("This file is invalid and cannot be played.")),
588 ("atom has bogus size %" G_GUINT64_FORMAT, size));
589 return GST_FLOW_ERROR;
593 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
595 if (G_UNLIKELY (flow != GST_FLOW_OK))
598 bsize = gst_buffer_get_size (*buf);
599 /* Catch short reads - we don't want any partial atoms */
600 if (G_UNLIKELY (bsize < size)) {
601 GST_WARNING_OBJECT (qtdemux,
602 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
603 gst_buffer_unref (*buf);
613 gst_qtdemux_src_convert (GstPad * pad, GstFormat src_format, gint64 src_value,
614 GstFormat dest_format, gint64 * dest_value)
617 QtDemuxStream *stream = gst_pad_get_element_private (pad);
618 GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
621 if (stream->subtype != FOURCC_vide) {
626 switch (src_format) {
627 case GST_FORMAT_TIME:
628 switch (dest_format) {
629 case GST_FORMAT_BYTES:{
630 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
634 *dest_value = stream->samples[index].offset;
636 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
637 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
638 GST_TIME_ARGS (src_value), *dest_value);
646 case GST_FORMAT_BYTES:
647 switch (dest_format) {
648 case GST_FORMAT_TIME:{
650 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
657 gst_util_uint64_scale (stream->samples[index].timestamp,
658 GST_SECOND, stream->timescale);
659 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Offset->Time :%"
660 G_GUINT64_FORMAT "->%" GST_TIME_FORMAT,
661 src_value, GST_TIME_ARGS (*dest_value));
674 gst_object_unref (qtdemux);
681 gst_qtdemux_get_duration (GstQTDemux * qtdemux, gint64 * duration)
685 *duration = GST_CLOCK_TIME_NONE;
687 if (qtdemux->duration != 0) {
688 if (qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
689 *duration = gst_util_uint64_scale (qtdemux->duration,
690 GST_SECOND, qtdemux->timescale);
697 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
700 gboolean res = FALSE;
701 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
703 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
705 switch (GST_QUERY_TYPE (query)) {
706 case GST_QUERY_POSITION:
707 if (GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
708 gst_query_set_position (query, GST_FORMAT_TIME,
709 qtdemux->segment.position);
713 case GST_QUERY_DURATION:{
716 gst_query_parse_duration (query, &fmt, NULL);
717 if (fmt == GST_FORMAT_TIME) {
718 gint64 duration = -1;
720 gst_qtdemux_get_duration (qtdemux, &duration);
722 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
728 case GST_QUERY_CONVERT:{
729 GstFormat src_fmt, dest_fmt;
730 gint64 src_value, dest_value = 0;
732 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
734 res = gst_qtdemux_src_convert (pad,
735 src_fmt, src_value, dest_fmt, &dest_value);
737 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
742 case GST_QUERY_FORMATS:
743 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
746 case GST_QUERY_SEEKING:{
750 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
751 if (fmt == GST_FORMAT_TIME) {
752 gint64 duration = -1;
754 gst_qtdemux_get_duration (qtdemux, &duration);
756 if (!qtdemux->pullbased) {
759 /* we might be able with help from upstream */
761 q = gst_query_new_seeking (GST_FORMAT_BYTES);
762 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
763 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
764 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
768 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
774 res = gst_pad_query_default (pad, parent, query);
782 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
784 if (G_LIKELY (stream->pad)) {
785 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
786 GST_DEBUG_PAD_NAME (stream->pad));
788 if (G_UNLIKELY (stream->pending_tags)) {
789 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
790 stream->pending_tags);
791 gst_pad_push_event (stream->pad,
792 gst_event_new_tag (stream->pending_tags));
793 stream->pending_tags = NULL;
796 if (G_UNLIKELY (stream->send_global_tags && qtdemux->tag_list)) {
797 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
799 gst_pad_push_event (stream->pad,
800 gst_event_new_tag (gst_tag_list_copy (qtdemux->tag_list)));
801 stream->send_global_tags = FALSE;
806 /* push event on all source pads; takes ownership of the event */
808 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
811 gboolean has_valid_stream = FALSE;
812 GstEventType etype = GST_EVENT_TYPE (event);
814 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
815 GST_EVENT_TYPE_NAME (event));
817 for (n = 0; n < qtdemux->n_streams; n++) {
819 QtDemuxStream *stream = qtdemux->streams[n];
821 if ((pad = stream->pad)) {
822 has_valid_stream = TRUE;
824 if (etype == GST_EVENT_EOS) {
825 /* let's not send twice */
826 if (stream->sent_eos)
828 stream->sent_eos = TRUE;
831 gst_pad_push_event (pad, gst_event_ref (event));
835 gst_event_unref (event);
837 /* if it is EOS and there are no pads, post an error */
838 if (!has_valid_stream && etype == GST_EVENT_EOS) {
839 gst_qtdemux_post_no_playable_stream_error (qtdemux);
843 /* push a pending newsegment event, if any from the streaming thread */
845 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
847 if (qtdemux->pending_newsegment) {
848 gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
849 qtdemux->pending_newsegment = NULL;
859 find_func (QtDemuxSample * s1, guint64 * media_time, gpointer user_data)
861 if (s1->timestamp > *media_time)
867 /* find the index of the sample that includes the data for @media_time using a
868 * binary search. Only to be called in optimized cases of linear search below.
870 * Returns the index of the sample.
873 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
876 QtDemuxSample *result;
879 /* convert media_time to mov format */
881 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
883 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
884 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
885 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
887 if (G_LIKELY (result))
888 index = result - str->samples;
897 /* find the index of the sample that includes the data for @media_offset using a
900 * Returns the index of the sample.
903 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
904 QtDemuxStream * str, gint64 media_offset)
906 QtDemuxSample *result = str->samples;
909 if (result == NULL || str->n_samples == 0)
912 if (media_offset == result->offset)
916 while (index < str->n_samples - 1) {
917 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
920 if (media_offset < result->offset)
931 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
936 /* find the index of the sample that includes the data for @media_time using a
937 * linear search, and keeping in mind that not all samples may have been parsed
938 * yet. If possible, it will delegate to binary search.
940 * Returns the index of the sample.
943 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
949 /* convert media_time to mov format */
951 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
953 if (mov_time == str->samples[0].timestamp)
956 /* use faster search if requested time in already parsed range */
957 if (str->stbl_index >= 0 &&
958 mov_time <= str->samples[str->stbl_index].timestamp)
959 return gst_qtdemux_find_index (qtdemux, str, media_time);
961 while (index < str->n_samples - 1) {
962 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
965 if (mov_time < str->samples[index + 1].timestamp)
975 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
980 /* find the index of the keyframe needed to decode the sample at @index
983 * Returns the index of the keyframe.
986 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
989 guint32 new_index = index;
991 if (index >= str->n_samples) {
992 new_index = str->n_samples;
996 /* all keyframes, return index */
997 if (str->all_keyframe) {
1002 /* else go back until we have a keyframe */
1004 if (str->samples[new_index].keyframe)
1014 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index before index %u "
1015 "gave %u", index, new_index);
1020 /* find the segment for @time_position for @stream
1022 * Returns -1 if the segment cannot be found.
1025 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1026 guint64 time_position)
1031 GST_LOG_OBJECT (qtdemux, "finding segment for %" GST_TIME_FORMAT,
1032 GST_TIME_ARGS (time_position));
1034 /* find segment corresponding to time_position if we are looking
1037 for (i = 0; i < stream->n_segments; i++) {
1038 QtDemuxSegment *segment = &stream->segments[i];
1040 GST_LOG_OBJECT (qtdemux,
1041 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1042 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1044 /* For the last segment we include stop_time in the last segment */
1045 if (i < stream->n_segments - 1) {
1046 if (segment->time <= time_position && time_position < segment->stop_time) {
1047 GST_LOG_OBJECT (qtdemux, "segment %d matches", i);
1052 if (segment->time <= time_position && time_position <= segment->stop_time) {
1053 GST_LOG_OBJECT (qtdemux, "segment %d matches", i);
1062 /* move the stream @str to the sample position @index.
1064 * Updates @str->sample_index and marks discontinuity if needed.
1067 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1070 /* no change needed */
1071 if (index == str->sample_index)
1074 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1077 /* position changed, we have a discont */
1078 str->sample_index = index;
1079 /* Each time we move in the stream we store the position where we are
1081 str->from_sample = index;
1082 str->discont = TRUE;
1086 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1087 gint64 * key_time, gint64 * key_offset)
1090 gint64 min_byte_offset = -1;
1093 min_offset = desired_time;
1095 /* for each stream, find the index of the sample in the segment
1096 * and move back to the previous keyframe. */
1097 for (n = 0; n < qtdemux->n_streams; n++) {
1099 guint32 index, kindex;
1101 guint64 media_start;
1104 QtDemuxSegment *seg;
1106 str = qtdemux->streams[n];
1108 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1109 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1111 /* segment not found, continue with normal flow */
1115 /* get segment and time in the segment */
1116 seg = &str->segments[seg_idx];
1117 seg_time = desired_time - seg->time;
1119 /* get the media time in the segment */
1120 media_start = seg->media_start + seg_time;
1122 /* get the index of the sample with media time */
1123 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1124 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1125 " at offset %" G_GUINT64_FORMAT,
1126 GST_TIME_ARGS (media_start), index, str->samples[index].offset);
1128 /* find previous keyframe */
1129 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index);
1131 /* if the keyframe is at a different position, we need to update the
1132 * requested seek time */
1133 if (index != kindex) {
1136 /* get timestamp of keyframe */
1138 gst_util_uint64_scale (str->samples[kindex].timestamp, GST_SECOND,
1140 GST_DEBUG_OBJECT (qtdemux, "keyframe at %u with time %" GST_TIME_FORMAT
1141 " at offset %" G_GUINT64_FORMAT,
1142 kindex, GST_TIME_ARGS (media_time), str->samples[kindex].offset);
1144 /* keyframes in the segment get a chance to change the
1145 * desired_offset. keyframes out of the segment are
1147 if (media_time >= seg->media_start) {
1150 /* this keyframe is inside the segment, convert back to
1152 seg_time = (media_time - seg->media_start) + seg->time;
1153 if (seg_time < min_offset)
1154 min_offset = seg_time;
1158 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1159 min_byte_offset = str->samples[index].offset;
1163 *key_time = min_offset;
1165 *key_offset = min_byte_offset;
1169 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1170 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1174 g_return_val_if_fail (format != NULL, FALSE);
1175 g_return_val_if_fail (cur != NULL, FALSE);
1176 g_return_val_if_fail (stop != NULL, FALSE);
1178 if (*format == GST_FORMAT_TIME)
1182 if (cur_type != GST_SEEK_TYPE_NONE)
1183 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1184 if (res && stop_type != GST_SEEK_TYPE_NONE)
1185 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1188 *format = GST_FORMAT_TIME;
1193 /* perform seek in push based mode:
1194 find BYTE position to move to based on time and delegate to upstream
1197 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1202 GstSeekType cur_type, stop_type;
1207 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1209 gst_event_parse_seek (event, &rate, &format, &flags,
1210 &cur_type, &cur, &stop_type, &stop);
1212 /* FIXME, always play to the end */
1215 /* only forward streaming and seeking is possible */
1217 goto unsupported_seek;
1219 /* convert to TIME if needed and possible */
1220 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1224 /* find reasonable corresponding BYTE position,
1225 * also try to mind about keyframes, since we can not go back a bit for them
1227 gst_qtdemux_adjust_seek (qtdemux, cur, NULL, &byte_cur);
1232 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1233 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1236 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1237 GST_DEBUG_OBJECT (qtdemux,
1238 "Requested seek time: %" GST_TIME_FORMAT ", calculated seek offset: %"
1239 G_GUINT64_FORMAT, GST_TIME_ARGS (cur), byte_cur);
1240 GST_OBJECT_LOCK (qtdemux);
1241 qtdemux->requested_seek_time = cur;
1242 qtdemux->seek_offset = byte_cur;
1243 GST_OBJECT_UNLOCK (qtdemux);
1246 /* BYTE seek event */
1247 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1249 res = gst_pad_push_event (qtdemux->sinkpad, event);
1256 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1262 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1267 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1272 /* perform the seek.
1274 * We set all segment_indexes in the streams to unknown and
1275 * adjust the time_position to the desired position. this is enough
1276 * to trigger a segment switch in the streaming thread to start
1277 * streaming from the desired position.
1279 * Keyframe seeking is a little more complicated when dealing with
1280 * segments. Ideally we want to move to the previous keyframe in
1281 * the segment but there might not be a keyframe in the segment. In
1282 * fact, none of the segments could contain a keyframe. We take a
1283 * practical approach: seek to the previous keyframe in the segment,
1284 * if there is none, seek to the beginning of the segment.
1286 * Called with STREAM_LOCK
1289 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment)
1291 gint64 desired_offset;
1294 desired_offset = segment->position;
1296 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1297 GST_TIME_ARGS (desired_offset));
1299 /* may not have enough fragmented info to do this adjustment,
1300 * and we can't scan (and probably should not) at this time with
1301 * possibly flushing upstream */
1302 if ((segment->flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1305 gst_qtdemux_adjust_seek (qtdemux, desired_offset, &min_offset, NULL);
1306 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1307 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1308 desired_offset = min_offset;
1311 /* and set all streams to the final position */
1312 for (n = 0; n < qtdemux->n_streams; n++) {
1313 QtDemuxStream *stream = qtdemux->streams[n];
1315 stream->time_position = desired_offset;
1316 stream->sample_index = -1;
1317 stream->segment_index = -1;
1318 stream->last_ret = GST_FLOW_OK;
1319 stream->sent_eos = FALSE;
1321 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1322 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1324 segment->position = desired_offset;
1325 segment->time = desired_offset;
1327 /* we stop at the end */
1328 if (segment->stop == -1)
1329 segment->stop = segment->duration;
1334 /* do a seek in pull based mode */
1336 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1341 GstSeekType cur_type, stop_type;
1345 GstSegment seeksegment;
1349 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1351 gst_event_parse_seek (event, &rate, &format, &flags,
1352 &cur_type, &cur, &stop_type, &stop);
1354 /* we have to have a format as the segment format. Try to convert
1356 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1360 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1362 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1366 flush = flags & GST_SEEK_FLAG_FLUSH;
1368 /* stop streaming, either by flushing or by pausing the task */
1370 /* unlock upstream pull_range */
1371 gst_pad_push_event (qtdemux->sinkpad, gst_event_new_flush_start ());
1372 /* make sure out loop function exits */
1373 gst_qtdemux_push_event (qtdemux, gst_event_new_flush_start ());
1375 /* non flushing seek, pause the task */
1376 gst_pad_pause_task (qtdemux->sinkpad);
1379 /* wait for streaming to finish */
1380 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1382 /* copy segment, we need this because we still need the old
1383 * segment when we close the current segment. */
1384 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1387 /* configure the segment with the seek variables */
1388 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1389 gst_segment_do_seek (&seeksegment, rate, format, flags,
1390 cur_type, cur, stop_type, stop, &update);
1393 /* now do the seek, this actually never returns FALSE */
1394 gst_qtdemux_perform_seek (qtdemux, &seeksegment);
1396 /* prepare for streaming again */
1398 gst_pad_push_event (qtdemux->sinkpad, gst_event_new_flush_stop (TRUE));
1399 gst_qtdemux_push_event (qtdemux, gst_event_new_flush_stop (TRUE));
1402 /* commit the new segment */
1403 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1405 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1406 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
1407 gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1408 qtdemux->segment.format, qtdemux->segment.position));
1411 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1412 for (i = 0; i < qtdemux->n_streams; i++)
1413 qtdemux->streams[i]->last_ret = GST_FLOW_OK;
1415 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1418 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1425 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1431 qtdemux_ensure_index (GstQTDemux * qtdemux)
1435 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1437 /* Build complete index */
1438 for (i = 0; i < qtdemux->n_streams; i++) {
1439 QtDemuxStream *stream = qtdemux->streams[i];
1441 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1449 GST_LOG_OBJECT (qtdemux,
1450 "Building complete index of stream %u for seeking failed!", i);
1456 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1459 gboolean res = TRUE;
1460 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1462 switch (GST_EVENT_TYPE (event)) {
1463 case GST_EVENT_SEEK:
1465 #ifndef GST_DISABLE_GST_DEBUG
1466 GstClockTime ts = gst_util_get_timestamp ();
1468 /* Build complete index for seeking;
1469 * if not a fragmented file at least */
1470 if (!qtdemux->fragmented)
1471 if (!qtdemux_ensure_index (qtdemux))
1473 #ifndef GST_DISABLE_GST_DEBUG
1474 ts = gst_util_get_timestamp () - ts;
1475 GST_INFO_OBJECT (qtdemux,
1476 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1479 if (qtdemux->pullbased) {
1480 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1481 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams &&
1482 !qtdemux->fragmented) {
1483 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1485 GST_DEBUG_OBJECT (qtdemux,
1486 "ignoring seek in push mode in current state");
1489 gst_event_unref (event);
1492 case GST_EVENT_NAVIGATION:
1494 gst_event_unref (event);
1497 res = gst_pad_event_default (pad, parent, event);
1507 GST_ERROR_OBJECT (qtdemux, "Index failed");
1508 gst_event_unref (event);
1514 /* stream/index return sample that is min/max w.r.t. byte position,
1515 * time is min/max w.r.t. time of samples,
1516 * the latter need not be time of the former sample */
1518 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1519 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1522 gint64 time, min_time;
1523 QtDemuxStream *stream;
1529 for (n = 0; n < qtdemux->n_streams; ++n) {
1532 gboolean set_sample;
1534 str = qtdemux->streams[n];
1541 i = str->n_samples - 1;
1544 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1545 if (str->samples[i].size &&
1546 ((fw && (str->samples[i].offset >= byte_pos)) ||
1548 (str->samples[i].offset + str->samples[i].size <=
1550 /* move stream to first available sample */
1552 gst_qtdemux_move_stream (qtdemux, str, i);
1555 /* determine min/max time */
1556 time = str->samples[i].timestamp + str->samples[i].pts_offset;
1557 time = gst_util_uint64_scale (time, GST_SECOND, str->timescale);
1558 if (min_time == -1 || (!fw && time > min_time) ||
1559 (fw && time < min_time)) {
1562 /* determine stream with leading sample, to get its position */
1564 && (str->samples[i].offset < stream->samples[index].offset))
1566 && (str->samples[i].offset > stream->samples[index].offset))) {
1573 /* no sample for this stream, mark eos */
1575 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1587 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
1590 GstQTDemux *demux = GST_QTDEMUX (parent);
1593 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
1595 switch (GST_EVENT_TYPE (event)) {
1596 case GST_EVENT_SEGMENT:
1599 QtDemuxStream *stream;
1603 /* some debug output */
1604 gst_event_copy_segment (event, &segment);
1605 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
1608 /* chain will send initial newsegment after pads have been added */
1609 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
1610 GST_DEBUG_OBJECT (demux, "still starting, eating event");
1614 /* we only expect a BYTE segment, e.g. following a seek */
1615 if (segment.format == GST_FORMAT_BYTES) {
1616 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
1617 gint64 requested_seek_time;
1618 guint64 seek_offset;
1620 offset = segment.start;
1622 GST_OBJECT_LOCK (demux);
1623 requested_seek_time = demux->requested_seek_time;
1624 seek_offset = demux->seek_offset;
1625 demux->requested_seek_time = -1;
1626 demux->seek_offset = -1;
1627 GST_OBJECT_UNLOCK (demux);
1629 if (offset == seek_offset) {
1630 segment.start = requested_seek_time;
1632 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
1633 NULL, (gint64 *) & segment.start);
1634 if ((gint64) segment.start < 0)
1638 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
1639 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
1640 NULL, (gint64 *) & segment.stop);
1641 /* keyframe seeking should already arrange for start >= stop,
1642 * but make sure in other rare cases */
1643 segment.stop = MAX (segment.stop, segment.start);
1646 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
1650 /* accept upstream's notion of segment and distribute along */
1651 segment.time = segment.start;
1652 segment.duration = demux->segment.duration;
1653 segment.base = gst_segment_to_running_time (&demux->segment,
1654 GST_FORMAT_TIME, demux->segment.position);
1656 gst_segment_copy_into (&segment, &demux->segment);
1657 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
1658 gst_qtdemux_push_event (demux, gst_event_new_segment (&segment));
1660 /* clear leftover in current segment, if any */
1661 gst_adapter_clear (demux->adapter);
1662 /* set up streaming thread */
1663 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx, NULL);
1664 demux->offset = offset;
1666 demux->todrop = stream->samples[idx].offset - offset;
1667 demux->neededbytes = demux->todrop + stream->samples[idx].size;
1669 /* set up for EOS */
1670 demux->neededbytes = -1;
1674 gst_event_unref (event);
1679 case GST_EVENT_FLUSH_STOP:
1684 /* clean up, force EOS if no more info follows */
1685 gst_adapter_clear (demux->adapter);
1687 demux->neededbytes = -1;
1688 /* reset flow return, e.g. following seek */
1689 for (i = 0; i < demux->n_streams; i++) {
1690 demux->streams[i]->last_ret = GST_FLOW_OK;
1691 demux->streams[i]->sent_eos = FALSE;
1693 dur = demux->segment.duration;
1694 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
1695 demux->segment.duration = dur;
1699 /* If we are in push mode, and get an EOS before we've seen any streams,
1700 * then error out - we have nowhere to send the EOS */
1701 if (!demux->pullbased) {
1703 gboolean has_valid_stream = FALSE;
1704 for (i = 0; i < demux->n_streams; i++) {
1705 if (demux->streams[i]->pad != NULL) {
1706 has_valid_stream = TRUE;
1710 if (!has_valid_stream)
1711 gst_qtdemux_post_no_playable_stream_error (demux);
1718 res = gst_pad_event_default (demux->sinkpad, parent, event);
1726 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
1728 GstQTDemux *demux = GST_QTDEMUX (element);
1730 GST_OBJECT_LOCK (demux);
1731 if (demux->element_index)
1732 gst_object_unref (demux->element_index);
1734 demux->element_index = gst_object_ref (index);
1736 demux->element_index = NULL;
1738 GST_OBJECT_UNLOCK (demux);
1739 /* object lock might be taken again */
1741 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
1742 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
1743 demux->element_index, demux->index_id);
1747 gst_qtdemux_get_index (GstElement * element)
1749 GstIndex *result = NULL;
1750 GstQTDemux *demux = GST_QTDEMUX (element);
1752 GST_OBJECT_LOCK (demux);
1753 if (demux->element_index)
1754 result = gst_object_ref (demux->element_index);
1755 GST_OBJECT_UNLOCK (demux);
1757 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
1764 gst_qtdemux_stbl_free (QtDemuxStream * stream)
1766 g_free ((gpointer) stream->stco.data);
1767 stream->stco.data = NULL;
1768 g_free ((gpointer) stream->stsz.data);
1769 stream->stsz.data = NULL;
1770 g_free ((gpointer) stream->stsc.data);
1771 stream->stsc.data = NULL;
1772 g_free ((gpointer) stream->stts.data);
1773 stream->stts.data = NULL;
1774 g_free ((gpointer) stream->stss.data);
1775 stream->stss.data = NULL;
1776 g_free ((gpointer) stream->stps.data);
1777 stream->stps.data = NULL;
1778 g_free ((gpointer) stream->ctts.data);
1779 stream->ctts.data = NULL;
1783 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
1785 while (stream->buffers) {
1786 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
1787 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
1790 gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
1791 g_free (stream->samples);
1793 gst_caps_unref (stream->caps);
1794 g_free (stream->segments);
1795 if (stream->pending_tags)
1796 gst_tag_list_free (stream->pending_tags);
1797 g_free (stream->redirect_uri);
1798 /* free stbl sub-atoms */
1799 gst_qtdemux_stbl_free (stream);
1803 static GstStateChangeReturn
1804 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
1806 GstQTDemux *qtdemux = GST_QTDEMUX (element);
1807 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
1809 switch (transition) {
1810 case GST_STATE_CHANGE_PAUSED_TO_READY:
1816 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1818 switch (transition) {
1819 case GST_STATE_CHANGE_PAUSED_TO_READY:{
1822 qtdemux->state = QTDEMUX_STATE_INITIAL;
1823 qtdemux->neededbytes = 16;
1824 qtdemux->todrop = 0;
1825 qtdemux->pullbased = FALSE;
1826 qtdemux->posted_redirect = FALSE;
1827 qtdemux->offset = 0;
1828 qtdemux->first_mdat = -1;
1829 qtdemux->header_size = 0;
1830 qtdemux->got_moov = FALSE;
1831 qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
1832 if (qtdemux->mdatbuffer)
1833 gst_buffer_unref (qtdemux->mdatbuffer);
1834 qtdemux->mdatbuffer = NULL;
1835 if (qtdemux->comp_brands)
1836 gst_buffer_unref (qtdemux->comp_brands);
1837 qtdemux->comp_brands = NULL;
1838 if (qtdemux->tag_list)
1839 gst_tag_list_free (qtdemux->tag_list);
1840 qtdemux->tag_list = NULL;
1842 if (qtdemux->element_index)
1843 gst_object_unref (qtdemux->element_index);
1844 qtdemux->element_index = NULL;
1846 gst_adapter_clear (qtdemux->adapter);
1847 for (n = 0; n < qtdemux->n_streams; n++) {
1848 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
1849 qtdemux->streams[n] = NULL;
1851 qtdemux->major_brand = 0;
1852 qtdemux->n_streams = 0;
1853 qtdemux->n_video_streams = 0;
1854 qtdemux->n_audio_streams = 0;
1855 qtdemux->n_sub_streams = 0;
1856 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
1857 qtdemux->requested_seek_time = GST_CLOCK_TIME_NONE;
1858 qtdemux->seek_offset = 0;
1859 qtdemux->upstream_seekable = FALSE;
1860 qtdemux->upstream_size = 0;
1871 qtdemux_post_global_tags (GstQTDemux * qtdemux)
1873 if (qtdemux->tag_list) {
1874 /* all header tags ready and parsed, push them */
1875 GST_INFO_OBJECT (qtdemux, "posting global tags: %" GST_PTR_FORMAT,
1877 /* post now, send event on pads later */
1878 gst_element_post_message (GST_ELEMENT (qtdemux),
1879 gst_message_new_tag (GST_OBJECT (qtdemux),
1880 gst_tag_list_copy (qtdemux->tag_list)));
1885 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
1887 /* counts as header data */
1888 qtdemux->header_size += length;
1890 /* only consider at least a sufficiently complete ftyp atom */
1894 qtdemux->major_brand = QT_FOURCC (buffer + 8);
1895 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
1896 GST_FOURCC_ARGS (qtdemux->major_brand));
1897 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
1898 _gst_buffer_copy_into_mem (buf, 0, buffer + 16, length - 16);
1903 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist)
1905 /* Strip out bogus fields */
1907 gst_tag_list_remove_tag (taglist, GST_TAG_VIDEO_CODEC);
1909 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, taglist);
1911 if (qtdemux->tag_list) {
1912 /* prioritize native tags using _KEEP mode */
1913 gst_tag_list_insert (qtdemux->tag_list, taglist, GST_TAG_MERGE_KEEP);
1914 gst_tag_list_free (taglist);
1916 qtdemux->tag_list = taglist;
1921 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
1923 static guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
1924 0x97, 0xA9, 0x42, 0xE8,
1925 0x9C, 0x71, 0x99, 0x94,
1926 0x91, 0xE3, 0xAF, 0xAC
1930 /* counts as header data */
1931 qtdemux->header_size += length;
1933 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
1935 if (length <= offset + 16) {
1936 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
1940 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
1942 GstTagList *taglist;
1944 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
1945 length - offset - 16, NULL);
1946 taglist = gst_tag_list_from_xmp_buffer (buf);
1947 gst_buffer_unref (buf);
1949 qtdemux_handle_xmp_taglist (qtdemux, taglist);
1952 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid");
1956 /* caller verifies at least 8 bytes in buf */
1958 extract_initial_length_and_fourcc (const guint8 * data, guint size,
1959 guint64 * plength, guint32 * pfourcc)
1964 length = QT_UINT32 (data);
1965 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
1966 fourcc = QT_FOURCC (data + 4);
1967 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
1970 length = G_MAXUINT32;
1971 } else if (length == 1 && size >= 16) {
1972 /* this means we have an extended size, which is the 64 bit value of
1973 * the next 8 bytes */
1974 length = QT_UINT64 (data + 8);
1975 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
1985 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
1987 guint32 version = 0;
1988 guint64 duration = 0;
1990 if (!gst_byte_reader_get_uint32_be (br, &version))
1995 if (!gst_byte_reader_get_uint64_be (br, &duration))
2000 if (!gst_byte_reader_get_uint32_be (br, &dur))
2005 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
2006 qtdemux->duration = duration;
2012 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
2018 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
2019 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
2021 if (!stream->parsed_trex && qtdemux->moov_node) {
2023 GstByteReader trex_data;
2025 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
2027 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
2030 guint32 id = 0, dur = 0, size = 0, flags = 0;
2032 /* skip version/flags */
2033 if (!gst_byte_reader_skip (&trex_data, 4))
2035 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
2037 if (id != stream->track_id)
2039 /* sample description index; ignore */
2040 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2042 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2044 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
2046 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
2049 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
2050 "duration %d, size %d, flags 0x%x", stream->track_id,
2053 stream->parsed_trex = TRUE;
2054 stream->def_sample_duration = dur;
2055 stream->def_sample_size = size;
2056 stream->def_sample_flags = flags;
2059 /* iterate all siblings */
2060 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
2066 *ds_duration = stream->def_sample_duration;
2067 *ds_size = stream->def_sample_size;
2068 *ds_size = stream->def_sample_size;
2070 /* even then, above values are better than random ... */
2071 if (G_UNLIKELY (!stream->parsed_trex)) {
2072 GST_WARNING_OBJECT (qtdemux,
2073 "failed to find fragment defaults for stream %d", stream->track_id);
2081 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
2082 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
2083 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
2084 gint64 * base_offset, gint64 * running_offset)
2087 gint32 data_offset = 0;
2088 guint32 flags = 0, first_flags = 0, samples_count = 0;
2091 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
2092 QtDemuxSample *sample;
2093 gboolean ismv = FALSE;
2095 GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
2096 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT,
2097 stream->track_id, d_sample_duration, d_sample_size, d_sample_flags,
2100 /* presence of stss or not can't really tell us much,
2101 * and flags and so on tend to be marginally reliable in these files */
2102 if (stream->subtype == FOURCC_soun) {
2103 GST_DEBUG_OBJECT (qtdemux,
2104 "sound track in fragmented file; marking all keyframes");
2105 stream->all_keyframe = TRUE;
2108 if (!gst_byte_reader_skip (trun, 1) ||
2109 !gst_byte_reader_get_uint24_be (trun, &flags))
2112 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
2115 if (flags & TR_DATA_OFFSET) {
2116 /* note this is really signed */
2117 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
2119 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
2120 /* default base offset = first byte of moof */
2121 if (*base_offset == -1) {
2122 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
2123 *base_offset = moof_offset;
2125 *running_offset = *base_offset + data_offset;
2127 /* if no offset at all, that would mean data starts at moof start,
2128 * which is a bit wrong and is ismv crappy way, so compensate
2129 * assuming data is in mdat following moof */
2130 if (*base_offset == -1) {
2131 *base_offset = moof_offset + moof_length + 8;
2132 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
2135 if (*running_offset == -1)
2136 *running_offset = *base_offset;
2139 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
2141 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
2142 data_offset, flags, samples_count);
2144 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2145 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
2146 GST_DEBUG_OBJECT (qtdemux,
2147 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
2148 flags ^= TR_FIRST_SAMPLE_FLAGS;
2150 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
2152 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
2156 /* FIXME ? spec says other bits should also be checked to determine
2157 * entry size (and prefix size for that matter) */
2159 dur_offset = size_offset = 0;
2160 if (flags & TR_SAMPLE_DURATION) {
2161 GST_LOG_OBJECT (qtdemux, "entry duration present");
2162 dur_offset = entry_size;
2165 if (flags & TR_SAMPLE_SIZE) {
2166 GST_LOG_OBJECT (qtdemux, "entry size present");
2167 size_offset = entry_size;
2170 if (flags & TR_SAMPLE_FLAGS) {
2171 GST_LOG_OBJECT (qtdemux, "entry flags present");
2172 flags_offset = entry_size;
2175 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2176 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
2177 ct_offset = entry_size;
2181 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
2183 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
2185 if (stream->n_samples >=
2186 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
2189 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
2190 stream->n_samples, (guint) sizeof (QtDemuxSample),
2191 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
2193 /* create a new array of samples if it's the first sample parsed */
2194 if (stream->n_samples == 0)
2195 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
2196 /* or try to reallocate it with space enough to insert the new samples */
2198 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
2199 stream->n_samples + samples_count);
2200 if (stream->samples == NULL)
2203 if (G_UNLIKELY (stream->n_samples == 0)) {
2204 /* the timestamp of the first sample is also provided by the tfra entry
2205 * but we shouldn't rely on it as it is at the end of files */
2208 /* subsequent fragments extend stream */
2210 stream->samples[stream->n_samples - 1].timestamp +
2211 stream->samples[stream->n_samples - 1].duration;
2213 sample = stream->samples + stream->n_samples;
2214 for (i = 0; i < samples_count; i++) {
2215 guint32 dur, size, sflags, ct;
2217 /* first read sample data */
2218 if (flags & TR_SAMPLE_DURATION) {
2219 dur = QT_UINT32 (data + dur_offset);
2221 dur = d_sample_duration;
2223 if (flags & TR_SAMPLE_SIZE) {
2224 size = QT_UINT32 (data + size_offset);
2226 size = d_sample_size;
2228 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2230 sflags = first_flags;
2232 sflags = d_sample_flags;
2234 } else if (flags & TR_SAMPLE_FLAGS) {
2235 sflags = QT_UINT32 (data + flags_offset);
2237 sflags = d_sample_flags;
2239 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2240 ct = QT_UINT32 (data + ct_offset);
2246 /* fill the sample information */
2247 sample->offset = *running_offset;
2248 sample->pts_offset = ct;
2249 sample->size = size;
2250 sample->timestamp = timestamp;
2251 sample->duration = dur;
2252 /* sample-is-difference-sample */
2253 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
2254 * now idea how it relates to bitfield other than massive LE/BE confusion */
2255 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
2256 *running_offset += size;
2261 stream->n_samples += samples_count;
2267 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
2272 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
2278 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
2279 "be larger than %uMB (broken file?)", stream->n_samples,
2280 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
2285 /* find stream with @id */
2286 static inline QtDemuxStream *
2287 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
2289 QtDemuxStream *stream;
2293 if (G_UNLIKELY (!id)) {
2294 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
2298 /* try to get it fast and simple */
2299 if (G_LIKELY (id <= qtdemux->n_streams)) {
2300 stream = qtdemux->streams[id - 1];
2301 if (G_LIKELY (stream->track_id == id))
2305 /* linear search otherwise */
2306 for (i = 0; i < qtdemux->n_streams; i++) {
2307 stream = qtdemux->streams[i];
2308 if (stream->track_id == id)
2316 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
2317 QtDemuxStream ** stream, guint32 * default_sample_duration,
2318 guint32 * default_sample_size, guint32 * default_sample_flags,
2319 gint64 * base_offset)
2322 guint32 track_id = 0;
2324 if (!gst_byte_reader_skip (tfhd, 1) ||
2325 !gst_byte_reader_get_uint24_be (tfhd, &flags))
2328 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
2331 *stream = qtdemux_find_stream (qtdemux, track_id);
2332 if (G_UNLIKELY (!*stream))
2333 goto unknown_stream;
2335 if (flags & TF_BASE_DATA_OFFSET)
2336 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
2339 /* obtain stream defaults */
2340 qtdemux_parse_trex (qtdemux, *stream,
2341 default_sample_duration, default_sample_size, default_sample_flags);
2343 /* FIXME: Handle TF_SAMPLE_DESCRIPTION_INDEX properly */
2344 if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
2345 if (!gst_byte_reader_skip (tfhd, 4))
2348 if (flags & TF_DEFAULT_SAMPLE_DURATION)
2349 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
2352 if (flags & TF_DEFAULT_SAMPLE_SIZE)
2353 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
2356 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
2357 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
2364 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
2369 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
2375 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
2376 guint64 moof_offset, QtDemuxStream * stream)
2378 GNode *moof_node, *traf_node, *tfhd_node, *trun_node;
2379 GstByteReader trun_data, tfhd_data;
2380 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
2381 gint64 base_offset, running_offset;
2383 /* NOTE @stream ignored */
2385 moof_node = g_node_new ((guint8 *) buffer);
2386 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
2387 qtdemux_node_dump (qtdemux, moof_node);
2389 /* unknown base_offset to start with */
2390 base_offset = running_offset = -1;
2391 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
2393 /* Fragment Header node */
2395 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
2399 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
2400 &ds_size, &ds_flags, &base_offset))
2402 if (G_UNLIKELY (!stream)) {
2403 /* we lost track of offset, we'll need to regain it,
2404 * but can delay complaining until later or avoid doing so altogether */
2408 if (G_UNLIKELY (base_offset < -1))
2410 /* Track Run node */
2412 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
2415 qtdemux_parse_trun (qtdemux, &trun_data, stream,
2416 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
2418 /* iterate all siblings */
2419 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
2422 /* if no new base_offset provided for next traf,
2423 * base is end of current traf */
2424 base_offset = running_offset;
2425 running_offset = -1;
2427 /* iterate all siblings */
2428 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
2430 g_node_destroy (moof_node);
2435 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
2440 GST_DEBUG_OBJECT (qtdemux, "lost offset");
2445 g_node_destroy (moof_node);
2446 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
2447 (_("This file is corrupt and cannot be played.")), (NULL));
2452 /* might be used if some day we actually use mfra & co
2453 * for random access to fragments,
2454 * but that will require quite some modifications and much less relying
2455 * on a sample array */
2458 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node,
2459 QtDemuxStream * stream)
2461 guint64 time = 0, moof_offset = 0;
2462 guint32 ver_flags, track_id, len, num_entries, i;
2463 guint value_size, traf_size, trun_size, sample_size;
2464 GstBuffer *buf = NULL;
2468 gst_byte_reader_init (&tfra, (guint8 *) tfra_node->data + (4 + 4),
2469 QT_UINT32 ((guint8 *) tfra_node->data) - (4 + 4));
2471 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
2474 if (!(gst_byte_reader_get_uint32_be (&tfra, &track_id) &&
2475 gst_byte_reader_get_uint32_be (&tfra, &len) &&
2476 gst_byte_reader_get_uint32_be (&tfra, &num_entries)))
2479 GST_LOG_OBJECT (qtdemux, "id %d == stream id %d ?",
2480 track_id, stream->track_id);
2481 if (track_id != stream->track_id) {
2485 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
2486 sample_size = (len & 3) + 1;
2487 trun_size = ((len & 12) >> 2) + 1;
2488 traf_size = ((len & 48) >> 4) + 1;
2490 if (num_entries == 0)
2493 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
2494 value_size + value_size + traf_size + trun_size + sample_size))
2497 for (i = 0; i < num_entries; i++) {
2498 qt_atom_parser_get_offset (&tfra, value_size, &time);
2499 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
2500 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
2501 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
2502 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
2504 GST_LOG_OBJECT (qtdemux,
2505 "fragment time: %" GST_TIME_FORMAT " moof_offset: %u",
2506 GST_TIME_ARGS (gst_util_uint64_scale (time, GST_SECOND,
2507 stream->timescale)), moof_offset);
2509 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
2510 if (ret != GST_FLOW_OK)
2512 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
2513 moof_offset, stream);
2514 gst_buffer_unref (buf);
2522 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
2523 (_("This file is corrupt and cannot be played.")), (NULL));
2528 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
2534 qtdemux_parse_mfra (GstQTDemux * qtdemux, QtDemuxStream * stream)
2537 GNode *mfra_node, *tfra_node;
2540 if (!qtdemux->mfra_offset)
2543 ret = gst_qtdemux_pull_atom (qtdemux, qtdemux->mfra_offset, 0, &buffer);
2544 if (ret != GST_FLOW_OK)
2547 mfra_node = g_node_new ((guint8 *) GST_BUFFER_DATA (buffer));
2548 qtdemux_parse_node (qtdemux, mfra_node, GST_BUFFER_DATA (buffer),
2549 GST_BUFFER_SIZE (buffer));
2551 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
2554 qtdemux_parse_tfra (qtdemux, tfra_node, stream);
2555 /* iterate all siblings */
2556 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
2558 g_node_destroy (mfra_node);
2559 gst_buffer_unref (buffer);
2565 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
2566 (_("This file is corrupt and cannot be played.")), (NULL));
2571 static GstFlowReturn
2572 qtdemux_parse_mfro (GstQTDemux * qtdemux, guint64 * mfra_offset,
2573 guint32 * mfro_size)
2575 GstFlowReturn ret = GST_FLOW_ERROR;
2576 GstBuffer *mfro = NULL;
2579 GstFormat fmt = GST_FORMAT_BYTES;
2581 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, &fmt, &len)) {
2582 GST_DEBUG_OBJECT (qtdemux, "upstream size not available; "
2583 "can not locate mfro");
2587 ret = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
2588 if (ret != GST_FLOW_OK)
2591 fourcc = QT_FOURCC (GST_BUFFER_DATA (mfro) + 4);
2592 if (fourcc != FOURCC_mfro)
2595 GST_INFO_OBJECT (qtdemux, "Found mfro atom: fragmented mp4 container");
2596 if (GST_BUFFER_SIZE (mfro) >= 16) {
2597 GST_DEBUG_OBJECT (qtdemux, "parsing 'mfro' atom");
2598 *mfro_size = QT_UINT32 (GST_BUFFER_DATA (mfro) + 12);
2599 if (*mfro_size >= len) {
2600 GST_WARNING_OBJECT (qtdemux, "mfro.size is invalid");
2601 ret = GST_FLOW_ERROR;
2604 *mfra_offset = len - *mfro_size;
2609 gst_buffer_unref (mfro);
2615 qtdemux_parse_fragmented (GstQTDemux * qtdemux)
2618 guint32 mfra_size = 0;
2619 guint64 mfra_offset = 0;
2622 qtdemux->fragmented = FALSE;
2624 /* We check here if it is a fragmented mp4 container */
2625 ret = qtdemux_parse_mfro (qtdemux, &mfra_offset, &mfra_size);
2626 if (ret == GST_FLOW_OK && mfra_size != 0 && mfra_offset != 0) {
2627 qtdemux->fragmented = TRUE;
2628 GST_DEBUG_OBJECT (qtdemux,
2629 "mfra atom expected at offset %" G_GUINT64_FORMAT, mfra_offset);
2630 qtdemux->mfra_offset = mfra_offset;
2635 static GstFlowReturn
2636 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
2640 GstBuffer *buf = NULL;
2641 GstFlowReturn ret = GST_FLOW_OK;
2642 guint64 cur_offset = qtdemux->offset;
2645 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
2646 if (G_UNLIKELY (ret != GST_FLOW_OK))
2648 gst_buffer_map (buf, &map, GST_MAP_READ);
2649 if (G_LIKELY (map.size >= 8))
2650 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
2651 gst_buffer_unmap (buf, &map);
2652 gst_buffer_unref (buf);
2654 /* maybe we already got most we needed, so only consider this eof */
2655 if (G_UNLIKELY (length == 0)) {
2656 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
2657 (_("Invalid atom size.")),
2658 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
2659 GST_FOURCC_ARGS (fourcc)));
2666 /* record for later parsing when needed */
2667 if (!qtdemux->moof_offset) {
2668 qtdemux->moof_offset = qtdemux->offset;
2677 GST_LOG_OBJECT (qtdemux,
2678 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
2679 GST_FOURCC_ARGS (fourcc), cur_offset);
2680 qtdemux->offset += length;
2687 if (qtdemux->got_moov) {
2688 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
2689 qtdemux->offset += length;
2693 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
2694 if (ret != GST_FLOW_OK)
2696 gst_buffer_map (moov, &map, GST_MAP_READ);
2697 if (length != map.size) {
2698 /* Some files have a 'moov' atom at the end of the file which contains
2699 * a terminal 'free' atom where the body of the atom is missing.
2700 * Check for, and permit, this special case.
2702 if (map.size >= 8) {
2703 guint8 *final_data = map.data + (map.size - 8);
2704 guint32 final_length = QT_UINT32 (final_data);
2705 guint32 final_fourcc = QT_FOURCC (final_data + 4);
2706 gst_buffer_unmap (moov, &map);
2707 if (final_fourcc == FOURCC_free
2708 && map.size + final_length - 8 == length) {
2709 /* Ok, we've found that special case. Allocate a new buffer with
2710 * that free atom actually present. */
2711 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
2712 gst_buffer_copy_into (newmoov, moov, 0, 0, map.size);
2713 gst_buffer_map (newmoov, &map, GST_MAP_WRITE);
2714 memset (map.data + length - final_length + 8, 0, final_length - 8);
2715 gst_buffer_unref (moov);
2721 if (length != map.size) {
2722 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
2723 (_("This file is incomplete and cannot be played.")),
2724 ("We got less than expected (received %" G_GSIZE_FORMAT
2725 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
2726 (guint) length, cur_offset));
2727 gst_buffer_unmap (moov, &map);
2728 gst_buffer_unref (moov);
2729 ret = GST_FLOW_ERROR;
2732 qtdemux->offset += length;
2734 qtdemux_parse_moov (qtdemux, map.data, length);
2735 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
2737 qtdemux_parse_tree (qtdemux);
2738 g_node_destroy (qtdemux->moov_node);
2739 gst_buffer_unmap (moov, &map);
2740 gst_buffer_unref (moov);
2741 qtdemux->moov_node = NULL;
2742 qtdemux->got_moov = TRUE;
2750 /* extract major brand; might come in handy for ISO vs QT issues */
2751 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
2752 if (ret != GST_FLOW_OK)
2754 qtdemux->offset += length;
2755 gst_buffer_map (ftyp, &map, GST_MAP_READ);
2756 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
2757 gst_buffer_unmap (ftyp, &map);
2758 gst_buffer_unref (ftyp);
2765 /* uuid are extension atoms */
2766 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
2767 if (ret != GST_FLOW_OK)
2769 qtdemux->offset += length;
2770 gst_buffer_map (uuid, &map, GST_MAP_READ);
2771 qtdemux_parse_uuid (qtdemux, map.data, map.size);
2772 gst_buffer_unmap (uuid, &map);
2773 gst_buffer_unref (uuid);
2780 GST_LOG_OBJECT (qtdemux,
2781 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
2782 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
2784 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
2785 if (ret != GST_FLOW_OK)
2787 gst_buffer_map (unknown, &map, GST_MAP_READ);
2788 GST_MEMDUMP ("Unknown tag", map.data, map.size);
2789 gst_buffer_unmap (unknown, &map);
2790 gst_buffer_unref (unknown);
2791 qtdemux->offset += length;
2797 if (ret == GST_FLOW_EOS && qtdemux->got_moov) {
2798 /* digested all data, show what we have */
2799 ret = qtdemux_expose_streams (qtdemux);
2801 /* Only post, event on pads is done after newsegment */
2802 qtdemux_post_global_tags (qtdemux);
2804 qtdemux->state = QTDEMUX_STATE_MOVIE;
2805 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
2812 /* Seeks to the previous keyframe of the indexed stream and
2813 * aligns other streams with respect to the keyframe timestamp
2814 * of indexed stream. Only called in case of Reverse Playback
2816 static GstFlowReturn
2817 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
2820 guint32 seg_idx = 0, k_index = 0;
2821 guint32 ref_seg_idx, ref_k_index;
2822 guint64 k_pos = 0, last_stop = 0;
2823 QtDemuxSegment *seg = NULL;
2824 QtDemuxStream *ref_str = NULL;
2825 guint64 seg_media_start_mov; /* segment media start time in mov format */
2827 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
2828 * and finally align all the other streams on that timestamp with their
2829 * respective keyframes */
2830 for (n = 0; n < qtdemux->n_streams; n++) {
2831 QtDemuxStream *str = qtdemux->streams[n];
2833 seg_idx = gst_qtdemux_find_segment (qtdemux, str,
2834 qtdemux->segment.position);
2836 /* segment not found, continue with normal flow */
2840 /* No candidate yet, take that one */
2846 /* So that stream has a segment, we prefer video streams */
2847 if (str->subtype == FOURCC_vide) {
2853 if (G_UNLIKELY (!ref_str)) {
2854 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
2858 if (G_UNLIKELY (!ref_str->from_sample)) {
2859 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
2863 /* So that stream has been playing from from_sample to to_sample. We will
2864 * get the timestamp of the previous sample and search for a keyframe before
2865 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
2866 if (ref_str->subtype == FOURCC_vide) {
2867 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
2868 ref_str->from_sample - 1);
2870 if (ref_str->from_sample >= 10)
2871 k_index = ref_str->from_sample - 10;
2876 /* get current segment for that stream */
2877 seg = &ref_str->segments[ref_str->segment_index];
2878 /* convert seg->media_start to mov format time for timestamp comparison */
2879 seg_media_start_mov =
2880 gst_util_uint64_scale (seg->media_start, ref_str->timescale, GST_SECOND);
2881 /* Crawl back through segments to find the one containing this I frame */
2882 while (ref_str->samples[k_index].timestamp < seg_media_start_mov) {
2883 GST_DEBUG_OBJECT (qtdemux, "keyframe position is out of segment %u",
2884 ref_str->segment_index);
2885 if (G_UNLIKELY (!ref_str->segment_index)) {
2886 /* Reached first segment, let's consider it's EOS */
2889 ref_str->segment_index--;
2890 seg = &ref_str->segments[ref_str->segment_index];
2891 /* convert seg->media_start to mov format time for timestamp comparison */
2892 seg_media_start_mov =
2893 gst_util_uint64_scale (seg->media_start, ref_str->timescale,
2896 /* Calculate time position of the keyframe and where we should stop */
2898 (gst_util_uint64_scale (ref_str->samples[k_index].timestamp, GST_SECOND,
2899 ref_str->timescale) - seg->media_start) + seg->time;
2901 gst_util_uint64_scale (ref_str->samples[ref_str->from_sample].timestamp,
2902 GST_SECOND, ref_str->timescale);
2903 last_stop = (last_stop - seg->media_start) + seg->time;
2905 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
2906 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
2907 k_index, GST_TIME_ARGS (k_pos));
2909 /* Set last_stop with the keyframe timestamp we pushed of that stream */
2910 qtdemux->segment.position = last_stop;
2911 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
2912 GST_TIME_ARGS (last_stop));
2914 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
2915 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
2919 ref_seg_idx = ref_str->segment_index;
2920 ref_k_index = k_index;
2922 /* Align them all on this */
2923 for (n = 0; n < qtdemux->n_streams; n++) {
2925 guint64 media_start = 0, seg_time = 0;
2926 QtDemuxStream *str = qtdemux->streams[n];
2928 /* aligning reference stream again might lead to backing up to yet another
2929 * keyframe (due to timestamp rounding issues),
2930 * potentially putting more load on downstream; so let's try to avoid */
2931 if (str == ref_str) {
2932 seg_idx = ref_seg_idx;
2933 seg = &str->segments[seg_idx];
2934 k_index = ref_k_index;
2935 GST_DEBUG_OBJECT (qtdemux, "reference stream segment %d, "
2936 "sample at index %d", ref_str->segment_index, k_index);
2938 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
2939 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
2941 /* segment not found, continue with normal flow */
2945 /* get segment and time in the segment */
2946 seg = &str->segments[seg_idx];
2947 seg_time = k_pos - seg->time;
2949 /* get the media time in the segment */
2950 media_start = seg->media_start + seg_time;
2952 /* get the index of the sample with media time */
2953 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
2954 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u",
2955 GST_TIME_ARGS (media_start), index);
2957 /* find previous keyframe */
2958 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index);
2961 /* Remember until where we want to go */
2962 str->to_sample = str->from_sample - 1;
2963 /* Define our time position */
2964 str->time_position =
2965 (gst_util_uint64_scale (str->samples[k_index].timestamp, GST_SECOND,
2966 str->timescale) - seg->media_start) + seg->time;
2967 /* Now seek back in time */
2968 gst_qtdemux_move_stream (qtdemux, str, k_index);
2969 GST_DEBUG_OBJECT (qtdemux, "keyframe at %u, time position %"
2970 GST_TIME_FORMAT " playing from sample %u to %u", k_index,
2971 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
2977 return GST_FLOW_EOS;
2980 /* activate the given segment number @seg_idx of @stream at time @offset.
2981 * @offset is an absolute global position over all the segments.
2983 * This will push out a NEWSEGMENT event with the right values and
2984 * position the stream index to the first decodable sample before
2988 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
2989 guint32 seg_idx, guint64 offset)
2992 QtDemuxSegment *segment;
2993 guint32 index, kf_index;
2995 guint64 start, stop, time;
2998 GST_LOG_OBJECT (qtdemux, "activate segment %d, offset %" G_GUINT64_FORMAT,
3001 /* update the current segment */
3002 stream->segment_index = seg_idx;
3004 /* get the segment */
3005 segment = &stream->segments[seg_idx];
3007 if (G_UNLIKELY (offset < segment->time)) {
3008 GST_WARNING_OBJECT (qtdemux, "offset < segment->time %" G_GUINT64_FORMAT,
3013 /* segment lies beyond total indicated duration */
3014 if (G_UNLIKELY (qtdemux->segment.duration != -1 &&
3015 segment->time > qtdemux->segment.duration)) {
3016 GST_WARNING_OBJECT (qtdemux, "file duration %" G_GINT64_FORMAT
3017 " < segment->time %" G_GUINT64_FORMAT, qtdemux->segment.duration,
3022 /* get time in this segment */
3023 seg_time = offset - segment->time;
3025 GST_LOG_OBJECT (qtdemux, "seg_time %" GST_TIME_FORMAT,
3026 GST_TIME_ARGS (seg_time));
3028 if (G_UNLIKELY (seg_time > segment->duration)) {
3029 GST_LOG_OBJECT (qtdemux, "seg_time > segment->duration %" GST_TIME_FORMAT,
3030 GST_TIME_ARGS (segment->duration));
3034 /* qtdemux->segment.stop is in outside-time-realm, whereas
3035 * segment->media_stop is in track-time-realm.
3037 * In order to compare the two, we need to bring segment.stop
3038 * into the track-time-realm */
3040 stop = qtdemux->segment.stop;
3042 stop = qtdemux->segment.duration;
3044 stop = segment->media_stop;
3047 MIN (segment->media_stop, stop - segment->time + segment->media_start);
3049 if (qtdemux->segment.rate >= 0) {
3050 start = MIN (segment->media_start + seg_time, stop);
3053 if (segment->media_start >= qtdemux->segment.start) {
3054 start = segment->media_start;
3055 time = segment->time;
3057 start = qtdemux->segment.start;
3058 time = segment->time + (qtdemux->segment.start - segment->media_start);
3061 start = MAX (segment->media_start, qtdemux->segment.start);
3062 stop = MIN (segment->media_start + seg_time, stop);
3065 GST_DEBUG_OBJECT (qtdemux, "newsegment %d from %" GST_TIME_FORMAT
3066 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
3067 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
3069 /* combine global rate with that of the segment */
3070 rate = segment->rate * qtdemux->segment.rate;
3072 /* update the segment values used for clipping */
3073 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
3074 /* accumulate previous segments */
3075 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
3076 stream->segment.base += (stream->segment.stop - stream->segment.start) /
3077 ABS (stream->segment.rate);
3078 stream->segment.rate = rate;
3079 stream->segment.start = start;
3080 stream->segment.stop = stop;
3081 stream->segment.time = time;
3083 /* now prepare and send the segment */
3085 event = gst_event_new_segment (&stream->segment);
3086 gst_pad_push_event (stream->pad, event);
3087 /* assume we can send more data now */
3088 stream->last_ret = GST_FLOW_OK;
3089 /* clear to send tags on this pad now */
3090 gst_qtdemux_push_tags (qtdemux, stream);
3093 /* and move to the keyframe before the indicated media time of the
3095 if (qtdemux->segment.rate >= 0) {
3096 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
3097 stream->to_sample = G_MAXUINT32;
3098 GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
3099 ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
3100 GST_TIME_ARGS (gst_util_uint64_scale (stream->samples[index].timestamp,
3101 GST_SECOND, stream->timescale)));
3103 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
3104 stream->to_sample = index;
3105 GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
3106 ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
3107 GST_TIME_ARGS (gst_util_uint64_scale (stream->samples[index].timestamp,
3108 GST_SECOND, stream->timescale)));
3111 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
3112 * encountered an error and printed a message so we return appropriately */
3116 /* we're at the right spot */
3117 if (index == stream->sample_index) {
3118 GST_DEBUG_OBJECT (qtdemux, "we are at the right index");
3122 /* find keyframe of the target index */
3123 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index);
3126 /* indent does stupid stuff with stream->samples[].timestamp */
3128 /* if we move forwards, we don't have to go back to the previous
3129 * keyframe since we already sent that. We can also just jump to
3130 * the keyframe right before the target index if there is one. */
3131 if (index > stream->sample_index) {
3132 /* moving forwards check if we move past a keyframe */
3133 if (kf_index > stream->sample_index) {
3134 GST_DEBUG_OBJECT (qtdemux,
3135 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT, kf_index,
3136 GST_TIME_ARGS (gst_util_uint64_scale (
3137 stream->samples[kf_index].timestamp,
3138 GST_SECOND, stream->timescale)));
3139 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
3141 GST_DEBUG_OBJECT (qtdemux,
3142 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT
3143 " already sent", kf_index,
3144 GST_TIME_ARGS (gst_util_uint64_scale (
3145 stream->samples[kf_index].timestamp,
3146 GST_SECOND, stream->timescale)));
3149 GST_DEBUG_OBJECT (qtdemux,
3150 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT, kf_index,
3151 GST_TIME_ARGS (gst_util_uint64_scale (
3152 stream->samples[kf_index].timestamp,
3153 GST_SECOND, stream->timescale)));
3154 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
3162 /* prepare to get the current sample of @stream, getting essential values.
3164 * This function will also prepare and send the segment when needed.
3166 * Return FALSE if the stream is EOS.
3169 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
3170 QtDemuxStream * stream, guint64 * offset, guint * size, guint64 * dts,
3171 guint64 * pts, guint64 * duration, gboolean * keyframe)
3173 QtDemuxSample *sample;
3174 guint64 time_position;
3177 g_return_val_if_fail (stream != NULL, FALSE);
3179 time_position = stream->time_position;
3180 if (G_UNLIKELY (time_position == -1))
3183 seg_idx = stream->segment_index;
3184 if (G_UNLIKELY (seg_idx == -1)) {
3185 /* find segment corresponding to time_position if we are looking
3187 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
3189 /* nothing found, we're really eos */
3194 /* different segment, activate it, sample_index will be set. */
3195 if (G_UNLIKELY (stream->segment_index != seg_idx))
3196 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
3198 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
3199 stream->sample_index, stream->n_samples);
3201 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
3204 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
3205 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
3206 stream->sample_index);
3210 /* now get the info for the sample we're at */
3211 sample = &stream->samples[stream->sample_index];
3213 *dts = QTSAMPLE_DTS (stream, sample);
3214 *pts = QTSAMPLE_PTS (stream, sample);
3215 *offset = sample->offset;
3216 *size = sample->size;
3217 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
3218 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
3225 stream->time_position = -1;
3230 /* move to the next sample in @stream.
3232 * Moves to the next segment when needed.
3235 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
3237 QtDemuxSample *sample;
3238 QtDemuxSegment *segment;
3240 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
3241 /* Mark the stream as EOS */
3242 GST_DEBUG_OBJECT (qtdemux,
3243 "reached max allowed sample %u, mark EOS", stream->to_sample);
3244 stream->time_position = -1;
3248 /* move to next sample */
3249 stream->sample_index++;
3251 /* get current segment */
3252 segment = &stream->segments[stream->segment_index];
3254 /* reached the last sample, we need the next segment */
3255 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
3258 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
3259 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
3260 stream->sample_index);
3264 /* get next sample */
3265 sample = &stream->samples[stream->sample_index];
3267 /* see if we are past the segment */
3268 if (G_UNLIKELY (gst_util_uint64_scale (sample->timestamp,
3269 GST_SECOND, stream->timescale) >= segment->media_stop))
3272 if (gst_util_uint64_scale (sample->timestamp, GST_SECOND,
3273 stream->timescale) >= segment->media_start) {
3274 /* inside the segment, update time_position, looks very familiar to
3275 * GStreamer segments, doesn't it? */
3276 stream->time_position =
3277 (gst_util_uint64_scale (sample->timestamp, GST_SECOND,
3278 stream->timescale) - segment->media_start) + segment->time;
3280 /* not yet in segment, time does not yet increment. This means
3281 * that we are still prerolling keyframes to the decoder so it can
3282 * decode the first sample of the segment. */
3283 stream->time_position = segment->time;
3287 /* move to the next segment */
3290 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
3292 if (stream->segment_index == stream->n_segments - 1) {
3293 /* are we at the end of the last segment, we're EOS */
3294 stream->time_position = -1;
3296 /* else we're only at the end of the current segment */
3297 stream->time_position = segment->stop_time;
3299 /* make sure we select a new segment */
3300 stream->segment_index = -1;
3305 gst_qtdemux_sync_streams (GstQTDemux * demux)
3309 if (demux->n_streams <= 1)
3312 for (i = 0; i < demux->n_streams; i++) {
3313 QtDemuxStream *stream;
3314 GstClockTime end_time;
3316 stream = demux->streams[i];
3321 /* TODO advance time on subtitle streams here, if any some day */
3323 /* some clips/trailers may have unbalanced streams at the end,
3324 * so send EOS on shorter stream to prevent stalling others */
3326 /* do not mess with EOS if SEGMENT seeking */
3327 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
3330 if (demux->pullbased) {
3331 /* loop mode is sample time based */
3332 if (stream->time_position != -1)
3335 /* push mode is byte position based */
3336 if (stream->n_samples &&
3337 stream->samples[stream->n_samples - 1].offset >= demux->offset)
3341 if (stream->sent_eos)
3344 /* only act if some gap */
3345 end_time = stream->segments[stream->n_segments - 1].stop_time;
3346 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
3347 ", stream end: %" GST_TIME_FORMAT,
3348 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
3349 if (end_time + 2 * GST_SECOND < demux->segment.position) {
3350 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
3351 GST_PAD_NAME (stream->pad));
3352 stream->sent_eos = TRUE;
3353 gst_pad_push_event (stream->pad, gst_event_new_eos ());
3358 /* EOS and NOT_LINKED need to be combined. This means that we return:
3360 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
3361 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
3363 static GstFlowReturn
3364 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
3368 gboolean unexpected = FALSE, not_linked = TRUE;
3370 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
3372 /* store the value */
3373 stream->last_ret = ret;
3375 /* any other error that is not-linked or eos can be returned right away */
3376 if (G_LIKELY (ret != GST_FLOW_EOS && ret != GST_FLOW_NOT_LINKED))
3379 /* only return NOT_LINKED if all other pads returned NOT_LINKED */
3380 for (i = 0; i < demux->n_streams; i++) {
3381 QtDemuxStream *ostream = demux->streams[i];
3383 ret = ostream->last_ret;
3385 /* no unexpected or unlinked, return */
3386 if (G_LIKELY (ret != GST_FLOW_EOS && ret != GST_FLOW_NOT_LINKED))
3389 /* we check to see if we have at least 1 unexpected or all unlinked */
3390 unexpected |= (ret == GST_FLOW_EOS);
3391 not_linked &= (ret == GST_FLOW_NOT_LINKED);
3394 /* when we get here, we all have unlinked or unexpected */
3396 ret = GST_FLOW_NOT_LINKED;
3397 else if (unexpected)
3400 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
3404 /* the input buffer metadata must be writable. Returns NULL when the buffer is
3405 * completely cliped */
3407 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
3410 guint64 start, stop, cstart, cstop, diff;
3411 GstClockTime pts, dts, duration;
3413 gint num_rate, denom_rate;
3418 osize = size = gst_buffer_get_size (buf);
3421 /* depending on the type, setup the clip parameters */
3422 if (stream->subtype == FOURCC_soun) {
3423 frame_size = stream->bytes_per_frame;
3424 num_rate = GST_SECOND;
3425 denom_rate = (gint) stream->rate;
3427 } else if (stream->subtype == FOURCC_vide) {
3429 num_rate = stream->fps_n;
3430 denom_rate = stream->fps_d;
3435 /* we can only clip if we have a valid pts */
3436 pts = GST_BUFFER_PTS (buf);
3437 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
3440 dts = GST_BUFFER_DTS (buf);
3441 duration = GST_BUFFER_DURATION (buf);
3443 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
3445 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
3449 stop = start + duration;
3451 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
3452 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
3455 /* see if some clipping happened */
3456 diff = cstart - start;
3463 /* bring clipped time to samples and to bytes */
3464 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
3467 GST_DEBUG_OBJECT (qtdemux,
3468 "clipping start to %" GST_TIME_FORMAT " %"
3469 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
3475 diff = stop - cstop;
3480 /* bring clipped time to samples and then to bytes */
3481 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
3483 GST_DEBUG_OBJECT (qtdemux,
3484 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
3485 " bytes", GST_TIME_ARGS (cstop), diff);
3490 if (offset != 0 || size != osize)
3491 gst_buffer_resize (buf, offset, size);
3493 GST_BUFFER_DTS (buf) = dts;
3494 GST_BUFFER_PTS (buf) = pts;
3495 GST_BUFFER_DURATION (buf) = duration;
3499 /* dropped buffer */
3502 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
3507 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
3512 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
3513 gst_buffer_unref (buf);
3518 /* the input buffer metadata must be writable,
3519 * but time/duration etc not yet set and need not be preserved */
3521 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
3528 /* not many cases for now */
3529 if (G_UNLIKELY (stream->fourcc == FOURCC_mp4s)) {
3530 /* send a one time dvd clut event */
3531 if (stream->pending_event && stream->pad)
3532 gst_pad_push_event (stream->pad, stream->pending_event);
3533 stream->pending_event = NULL;
3534 /* no further processing needed */
3535 stream->need_process = FALSE;
3538 if (G_UNLIKELY (stream->subtype != FOURCC_text)) {
3542 gst_buffer_map (buf, &map, GST_MAP_READ);
3544 if (G_LIKELY (map.size >= 2)) {
3545 nsize = GST_READ_UINT16_BE (map.data);
3546 nsize = MIN (nsize, map.size - 2);
3549 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
3552 /* takes care of UTF-8 validation or UTF-16 recognition,
3553 * no other encoding expected */
3554 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
3555 gst_buffer_unmap (buf, &map);
3557 gst_buffer_unref (buf);
3558 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
3560 /* may be 0-size subtitle, which is also sent to keep pipeline going */
3561 gst_buffer_resize (buf, 2, nsize);
3564 /* FIXME ? convert optional subsequent style info to markup */
3569 /* Sets a buffer's attributes properly and pushes it downstream.
3570 * Also checks for additional actions and custom processing that may
3571 * need to be done first.
3574 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
3575 QtDemuxStream * stream, GstBuffer * buf,
3576 guint64 dts, guint64 pts, guint64 duration, gboolean keyframe,
3577 guint64 position, guint64 byte_position)
3579 GstFlowReturn ret = GST_FLOW_OK;
3581 if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) {
3585 gst_buffer_map (buf, &map, GST_MAP_READ);
3586 url = g_strndup ((gchar *) map.data, map.size);
3587 gst_buffer_unmap (buf, &map);
3588 if (url != NULL && strlen (url) != 0) {
3589 /* we have RTSP redirect now */
3590 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
3591 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
3592 gst_structure_new ("redirect",
3593 "new-location", G_TYPE_STRING, url, NULL)));
3594 qtdemux->posted_redirect = TRUE;
3596 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
3602 /* position reporting */
3603 if (qtdemux->segment.rate >= 0) {
3604 qtdemux->segment.position = position;
3605 gst_qtdemux_sync_streams (qtdemux);
3608 if (G_UNLIKELY (!stream->pad)) {
3609 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
3610 gst_buffer_unref (buf);
3614 /* send out pending buffers */
3615 while (stream->buffers) {
3616 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
3618 if (G_UNLIKELY (stream->discont)) {
3619 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
3620 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
3621 stream->discont = FALSE;
3624 gst_pad_push (stream->pad, buffer);
3626 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
3629 /* we're going to modify the metadata */
3630 buf = gst_buffer_make_writable (buf);
3632 if (G_UNLIKELY (stream->need_process))
3633 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
3635 GST_BUFFER_DTS (buf) = dts;
3636 GST_BUFFER_PTS (buf) = pts;
3637 GST_BUFFER_DURATION (buf) = duration;
3638 GST_BUFFER_OFFSET (buf) = -1;
3639 GST_BUFFER_OFFSET_END (buf) = -1;
3641 if (G_UNLIKELY (stream->padding)) {
3642 gst_buffer_resize (buf, stream->padding, -1);
3645 if (G_UNLIKELY (qtdemux->element_index)) {
3646 GstClockTime stream_time;
3649 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
3651 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
3652 GST_LOG_OBJECT (qtdemux,
3653 "adding association %" GST_TIME_FORMAT "-> %"
3654 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
3655 gst_index_add_association (qtdemux->element_index,
3657 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
3658 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
3659 GST_FORMAT_BYTES, byte_position, NULL);
3664 if (stream->need_clip)
3665 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
3667 if (G_UNLIKELY (buf == NULL))
3670 if (G_UNLIKELY (stream->discont)) {
3671 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
3672 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
3673 stream->discont = FALSE;
3677 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
3679 GST_LOG_OBJECT (qtdemux,
3680 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
3681 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
3682 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
3683 GST_PAD_NAME (stream->pad));
3685 ret = gst_pad_push (stream->pad, buf);
3691 static GstFlowReturn
3692 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
3694 GstFlowReturn ret = GST_FLOW_OK;
3695 GstBuffer *buf = NULL;
3696 QtDemuxStream *stream;
3699 guint64 dts = GST_CLOCK_TIME_NONE;
3700 guint64 pts = GST_CLOCK_TIME_NONE;
3701 guint64 duration = 0;
3702 gboolean keyframe = FALSE;
3707 gst_qtdemux_push_pending_newsegment (qtdemux);
3709 /* Figure out the next stream sample to output, min_time is expressed in
3710 * global time and runs over the edit list segments. */
3711 min_time = G_MAXUINT64;
3713 for (i = 0; i < qtdemux->n_streams; i++) {
3716 stream = qtdemux->streams[i];
3717 position = stream->time_position;
3719 /* position of -1 is EOS */
3720 if (position != -1 && position < min_time) {
3721 min_time = position;
3726 if (G_UNLIKELY (index == -1)) {
3727 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
3731 /* check for segment end */
3732 if (G_UNLIKELY (qtdemux->segment.stop != -1
3733 && qtdemux->segment.stop < min_time)) {
3734 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
3738 stream = qtdemux->streams[index];
3740 /* fetch info for the current sample of this stream */
3741 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &offset,
3742 &size, &dts, &pts, &duration, &keyframe)))
3745 GST_LOG_OBJECT (qtdemux,
3746 "pushing from stream %d, offset %" G_GUINT64_FORMAT
3747 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
3748 ", duration %" GST_TIME_FORMAT, index, offset, size,
3749 GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
3751 /* hmm, empty sample, skip and move to next sample */
3752 if (G_UNLIKELY (size <= 0))
3755 /* last pushed sample was out of boundary, goto next sample */
3756 if (G_UNLIKELY (stream->last_ret == GST_FLOW_EOS))
3759 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
3762 ret = gst_qtdemux_pull_atom (qtdemux, offset, size, &buf);
3763 if (G_UNLIKELY (ret != GST_FLOW_OK))
3766 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
3767 dts, pts, duration, keyframe, min_time, offset);
3770 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
3771 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
3772 * we have no more data for the pad to push */
3773 if (ret == GST_FLOW_EOS)
3777 gst_qtdemux_advance_sample (qtdemux, stream);
3785 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
3791 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
3792 /* EOS will be raised if all are EOS */
3799 gst_qtdemux_loop (GstPad * pad)
3801 GstQTDemux *qtdemux;
3805 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
3807 cur_offset = qtdemux->offset;
3808 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %d",
3809 cur_offset, qtdemux->state);
3811 switch (qtdemux->state) {
3812 case QTDEMUX_STATE_INITIAL:
3813 case QTDEMUX_STATE_HEADER:
3814 ret = gst_qtdemux_loop_state_header (qtdemux);
3816 case QTDEMUX_STATE_MOVIE:
3817 ret = gst_qtdemux_loop_state_movie (qtdemux);
3818 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
3819 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
3827 /* if something went wrong, pause */
3828 if (ret != GST_FLOW_OK)
3832 gst_object_unref (qtdemux);
3838 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
3839 (NULL), ("streaming stopped, invalid state"));
3840 gst_pad_pause_task (pad);
3841 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
3846 const gchar *reason = gst_flow_get_name (ret);
3848 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
3850 gst_pad_pause_task (pad);
3852 /* fatal errors need special actions */
3854 if (ret == GST_FLOW_EOS) {
3855 if (qtdemux->n_streams == 0) {
3856 /* we have no streams, post an error */
3857 gst_qtdemux_post_no_playable_stream_error (qtdemux);
3859 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
3862 if ((stop = qtdemux->segment.stop) == -1)
3863 stop = qtdemux->segment.duration;
3865 if (qtdemux->segment.rate >= 0) {
3866 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
3867 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
3868 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
3869 GST_FORMAT_TIME, stop));
3871 /* For Reverse Playback */
3872 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
3873 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
3874 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
3875 GST_FORMAT_TIME, qtdemux->segment.start));
3878 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
3879 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
3881 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
3882 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
3883 (NULL), ("streaming stopped, reason %s", reason));
3884 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
3893 * Returns the size of the first entry at the current offset.
3894 * If -1, there are none (which means EOS or empty file).
3897 next_entry_size (GstQTDemux * demux)
3899 QtDemuxStream *stream;
3902 guint64 smalloffs = (guint64) - 1;
3903 QtDemuxSample *sample;
3905 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
3908 for (i = 0; i < demux->n_streams; i++) {
3909 stream = demux->streams[i];
3911 if (stream->sample_index == -1)
3912 stream->sample_index = 0;
3914 if (stream->sample_index >= stream->n_samples) {
3915 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
3919 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
3920 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
3921 stream->sample_index);
3925 sample = &stream->samples[stream->sample_index];
3927 GST_LOG_OBJECT (demux,
3928 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
3929 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
3930 sample->offset, sample->size);
3932 if (((smalloffs == -1)
3933 || (sample->offset < smalloffs)) && (sample->size)) {
3935 smalloffs = sample->offset;
3939 GST_LOG_OBJECT (demux,
3940 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
3941 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
3946 stream = demux->streams[smallidx];
3947 sample = &stream->samples[stream->sample_index];
3949 if (sample->offset >= demux->offset) {
3950 demux->todrop = sample->offset - demux->offset;
3951 return sample->size + demux->todrop;
3954 GST_DEBUG_OBJECT (demux,
3955 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
3960 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
3962 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
3964 gst_element_post_message (GST_ELEMENT_CAST (demux),
3965 gst_message_new_element (GST_OBJECT_CAST (demux),
3966 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
3970 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
3975 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
3978 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
3979 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
3980 GST_SEEK_TYPE_NONE, -1);
3982 res = gst_pad_push_event (demux->sinkpad, event);
3987 /* check for seekable upstream, above and beyond a mere query */
3989 gst_qtdemux_check_seekability (GstQTDemux * demux)
3992 gboolean seekable = FALSE;
3993 gint64 start = -1, stop = -1;
3995 if (demux->upstream_size)
3998 query = gst_query_new_seeking (GST_FORMAT_BYTES);
3999 if (!gst_pad_peer_query (demux->sinkpad, query)) {
4000 GST_DEBUG_OBJECT (demux, "seeking query failed");
4004 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
4006 /* try harder to query upstream size if we didn't get it the first time */
4007 if (seekable && stop == -1) {
4008 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
4009 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
4012 /* if upstream doesn't know the size, it's likely that it's not seekable in
4013 * practice even if it technically may be seekable */
4014 if (seekable && (start != 0 || stop <= start)) {
4015 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
4020 gst_query_unref (query);
4022 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
4023 G_GUINT64_FORMAT ")", seekable, start, stop);
4024 demux->upstream_seekable = seekable;
4025 demux->upstream_size = seekable ? stop : -1;
4028 /* FIXME, unverified after edit list updates */
4029 static GstFlowReturn
4030 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
4033 GstFlowReturn ret = GST_FLOW_OK;
4035 demux = GST_QTDEMUX (parent);
4037 gst_adapter_push (demux->adapter, inbuf);
4039 /* we never really mean to buffer that much */
4040 if (demux->neededbytes == -1)
4043 GST_DEBUG_OBJECT (demux,
4044 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
4045 demux->neededbytes, gst_adapter_available (demux->adapter));
4047 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
4048 (ret == GST_FLOW_OK)) {
4050 GST_DEBUG_OBJECT (demux,
4051 "state:%d , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT,
4052 demux->state, demux->neededbytes, demux->offset);
4054 switch (demux->state) {
4055 case QTDEMUX_STATE_INITIAL:{
4060 gst_qtdemux_check_seekability (demux);
4062 data = gst_adapter_map (demux->adapter, demux->neededbytes);
4064 /* get fourcc/length, set neededbytes */
4065 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
4067 gst_adapter_unmap (demux->adapter);
4069 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
4070 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
4072 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4073 (_("This file is invalid and cannot be played.")),
4074 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
4075 GST_FOURCC_ARGS (fourcc)));
4076 ret = GST_FLOW_ERROR;
4079 if (fourcc == FOURCC_mdat) {
4080 if (demux->n_streams > 0) {
4081 /* we have the headers, start playback */
4082 demux->state = QTDEMUX_STATE_MOVIE;
4083 demux->neededbytes = next_entry_size (demux);
4084 demux->mdatleft = size;
4086 /* Only post, event on pads is done after newsegment */
4087 qtdemux_post_global_tags (demux);
4090 /* no headers yet, try to get them */
4093 guint64 old, target;
4096 old = demux->offset;
4097 target = old + size;
4099 /* try to jump over the atom with a seek */
4100 /* only bother if it seems worth doing so,
4101 * and avoids possible upstream/server problems */
4102 if (demux->upstream_seekable &&
4103 demux->upstream_size > 4 * (1 << 20)) {
4104 res = qtdemux_seek_offset (demux, target);
4106 GST_DEBUG_OBJECT (demux, "skipping seek");
4111 GST_DEBUG_OBJECT (demux, "seek success");
4112 /* remember the offset fo the first mdat so we can seek back to it
4113 * after we have the headers */
4114 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
4115 demux->first_mdat = old;
4116 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
4119 /* seek worked, continue reading */
4120 demux->offset = target;
4121 demux->neededbytes = 16;
4122 demux->state = QTDEMUX_STATE_INITIAL;
4124 /* seek failed, need to buffer */
4125 demux->offset = old;
4126 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
4127 /* there may be multiple mdat (or alike) buffers */
4129 if (demux->mdatbuffer)
4130 bs = gst_buffer_get_size (demux->mdatbuffer);
4133 if (size + bs > 10 * (1 << 20))
4135 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
4136 demux->neededbytes = size;
4137 if (!demux->mdatbuffer)
4138 demux->mdatoffset = demux->offset;
4141 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
4142 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4143 (_("This file is invalid and cannot be played.")),
4144 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
4145 GST_FOURCC_ARGS (fourcc), size));
4146 ret = GST_FLOW_ERROR;
4149 /* this means we already started buffering and still no moov header,
4150 * let's continue buffering everything till we get moov */
4151 if (demux->mdatbuffer && (fourcc != FOURCC_moov))
4153 demux->neededbytes = size;
4154 demux->state = QTDEMUX_STATE_HEADER;
4158 case QTDEMUX_STATE_HEADER:{
4162 GST_DEBUG_OBJECT (demux, "In header");
4164 data = gst_adapter_map (demux->adapter, demux->neededbytes);
4166 /* parse the header */
4167 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
4169 if (fourcc == FOURCC_moov) {
4170 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
4172 demux->got_moov = TRUE;
4174 /* prepare newsegment to send when streaming actually starts */
4175 if (!demux->pending_newsegment)
4176 demux->pending_newsegment = gst_event_new_segment (&demux->segment);
4178 qtdemux_parse_moov (demux, data, demux->neededbytes);
4179 qtdemux_node_dump (demux, demux->moov_node);
4180 qtdemux_parse_tree (demux);
4181 qtdemux_expose_streams (demux);
4183 g_node_destroy (demux->moov_node);
4184 demux->moov_node = NULL;
4185 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
4186 } else if (fourcc == FOURCC_moof) {
4187 if (demux->got_moov && demux->fragmented) {
4188 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
4189 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
4190 demux->offset, NULL)) {
4191 gst_adapter_unmap (demux->adapter);
4192 ret = GST_FLOW_ERROR;
4196 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
4198 } else if (fourcc == FOURCC_ftyp) {
4199 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
4200 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
4201 } else if (fourcc == FOURCC_uuid) {
4202 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
4203 qtdemux_parse_uuid (demux, data, demux->neededbytes);
4205 GST_WARNING_OBJECT (demux,
4206 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
4207 GST_FOURCC_ARGS (fourcc));
4208 /* Let's jump that one and go back to initial state */
4210 gst_adapter_unmap (demux->adapter);
4213 if (demux->mdatbuffer && demux->n_streams) {
4214 /* the mdat was before the header */
4215 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
4216 demux->n_streams, demux->mdatbuffer);
4217 /* restore our adapter/offset view of things with upstream;
4218 * put preceding buffered data ahead of current moov data.
4219 * This should also handle evil mdat, moov, mdat cases and alike */
4220 gst_adapter_clear (demux->adapter);
4221 gst_adapter_push (demux->adapter, demux->mdatbuffer);
4222 demux->mdatbuffer = NULL;
4223 demux->offset = demux->mdatoffset;
4224 demux->neededbytes = next_entry_size (demux);
4225 demux->state = QTDEMUX_STATE_MOVIE;
4226 demux->mdatleft = gst_adapter_available (demux->adapter);
4228 /* Only post, event on pads is done after newsegment */
4229 qtdemux_post_global_tags (demux);
4232 GST_DEBUG_OBJECT (demux, "Carrying on normally");
4233 gst_adapter_flush (demux->adapter, demux->neededbytes);
4235 if (demux->got_moov && demux->first_mdat != -1) {
4238 /* we need to seek back */
4239 res = qtdemux_seek_offset (demux, demux->first_mdat);
4241 demux->offset = demux->first_mdat;
4243 GST_DEBUG_OBJECT (demux, "Seek back failed");
4246 demux->offset += demux->neededbytes;
4248 demux->neededbytes = 16;
4249 demux->state = QTDEMUX_STATE_INITIAL;
4254 case QTDEMUX_STATE_BUFFER_MDAT:{
4258 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
4260 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
4261 gst_buffer_extract (buf, 0, fourcc, 4);
4262 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
4263 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
4264 if (demux->mdatbuffer)
4265 demux->mdatbuffer = gst_buffer_join (demux->mdatbuffer, buf);
4267 demux->mdatbuffer = buf;
4268 demux->offset += demux->neededbytes;
4269 demux->neededbytes = 16;
4270 demux->state = QTDEMUX_STATE_INITIAL;
4271 gst_qtdemux_post_progress (demux, 1, 1);
4275 case QTDEMUX_STATE_MOVIE:{
4277 QtDemuxStream *stream = NULL;
4278 QtDemuxSample *sample;
4280 guint64 dts, pts, duration;
4283 GST_DEBUG_OBJECT (demux,
4284 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
4286 if (demux->fragmented) {
4287 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
4289 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
4290 /* if needed data starts within this atom,
4291 * then it should not exceed this atom */
4292 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
4293 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4294 (_("This file is invalid and cannot be played.")),
4295 ("sample data crosses atom boundary"));
4296 ret = GST_FLOW_ERROR;
4299 demux->mdatleft -= demux->neededbytes;
4301 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
4302 /* so we are dropping more than left in this atom */
4303 demux->todrop -= demux->mdatleft;
4304 demux->neededbytes -= demux->mdatleft;
4305 demux->mdatleft = 0;
4306 /* need to resume atom parsing so we do not miss any other pieces */
4307 demux->state = QTDEMUX_STATE_INITIAL;
4308 demux->neededbytes = 16;
4313 if (demux->todrop) {
4314 GST_LOG_OBJECT (demux, "Dropping %d bytes", demux->todrop);
4315 gst_adapter_flush (demux->adapter, demux->todrop);
4316 demux->neededbytes -= demux->todrop;
4317 demux->offset += demux->todrop;
4321 /* initial newsegment sent here after having added pads,
4322 * possible others in sink_event */
4323 if (G_UNLIKELY (demux->pending_newsegment)) {
4324 gst_qtdemux_push_event (demux, demux->pending_newsegment);
4325 demux->pending_newsegment = NULL;
4326 /* clear to send tags on all streams */
4327 for (i = 0; i < demux->n_streams; i++) {
4328 gst_qtdemux_push_tags (demux, demux->streams[i]);
4332 /* Figure out which stream this is packet belongs to */
4333 for (i = 0; i < demux->n_streams; i++) {
4334 stream = demux->streams[i];
4335 if (stream->sample_index >= stream->n_samples)
4337 GST_LOG_OBJECT (demux,
4338 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
4339 " / size:%d)", i, stream->sample_index,
4340 stream->samples[stream->sample_index].offset,
4341 stream->samples[stream->sample_index].size);
4343 if (stream->samples[stream->sample_index].offset == demux->offset)
4347 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
4348 goto unknown_stream;
4350 /* Put data in a buffer, set timestamps, caps, ... */
4351 outbuf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
4352 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
4353 GST_FOURCC_ARGS (stream->fourcc));
4355 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
4357 sample = &stream->samples[stream->sample_index];
4359 dts = QTSAMPLE_DTS (stream, sample);
4360 pts = QTSAMPLE_PTS (stream, sample);
4361 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
4362 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
4364 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
4365 dts, pts, duration, keyframe, dts, demux->offset);
4368 ret = gst_qtdemux_combine_flows (demux, stream, ret);
4370 stream->sample_index++;
4372 /* update current offset and figure out size of next buffer */
4373 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
4374 demux->offset, demux->neededbytes);
4375 demux->offset += demux->neededbytes;
4376 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
4379 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
4380 if (demux->fragmented) {
4381 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
4382 /* there may be more to follow, only finish this atom */
4383 demux->todrop = demux->mdatleft;
4384 demux->neededbytes = demux->todrop;
4396 /* when buffering movie data, at least show user something is happening */
4397 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
4398 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
4399 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
4400 demux->neededbytes);
4409 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
4410 ret = GST_FLOW_ERROR;
4415 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
4421 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
4422 (NULL), ("qtdemuxer invalid state %d", demux->state));
4423 ret = GST_FLOW_ERROR;
4428 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
4429 (NULL), ("no 'moov' atom within the first 10 MB"));
4430 ret = GST_FLOW_ERROR;
4436 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
4441 query = gst_query_new_scheduling ();
4443 if (!gst_pad_peer_query (sinkpad, query)) {
4444 gst_query_unref (query);
4448 pull_mode = gst_query_has_scheduling_mode (query, GST_PAD_MODE_PULL);
4449 gst_query_unref (query);
4454 GST_DEBUG_OBJECT (sinkpad, "activating pull");
4455 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
4459 GST_DEBUG_OBJECT (sinkpad, "activating push");
4460 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
4465 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
4466 GstPadMode mode, gboolean active)
4469 GstQTDemux *demux = GST_QTDEMUX (parent);
4472 case GST_PAD_MODE_PUSH:
4473 demux->pullbased = FALSE;
4476 case GST_PAD_MODE_PULL:
4478 demux->pullbased = TRUE;
4479 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
4482 res = gst_pad_stop_task (sinkpad);
4494 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
4496 return g_malloc (items * size);
4500 qtdemux_zfree (void *opaque, void *addr)
4506 qtdemux_inflate (void *z_buffer, guint z_length, guint length)
4512 z = g_new0 (z_stream, 1);
4513 z->zalloc = qtdemux_zalloc;
4514 z->zfree = qtdemux_zfree;
4517 z->next_in = z_buffer;
4518 z->avail_in = z_length;
4520 buffer = (guint8 *) g_malloc (length);
4521 ret = inflateInit (z);
4522 while (z->avail_in > 0) {
4523 if (z->avail_out == 0) {
4525 buffer = (guint8 *) g_realloc (buffer, length);
4526 z->next_out = buffer + z->total_out;
4527 z->avail_out = 1024;
4529 ret = inflate (z, Z_SYNC_FLUSH);
4533 if (ret != Z_STREAM_END) {
4534 g_warning ("inflate() returned %d", ret);
4540 #endif /* HAVE_ZLIB */
4543 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
4547 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
4549 /* counts as header data */
4550 qtdemux->header_size += length;
4552 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
4553 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
4555 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
4561 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
4562 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
4563 if (dcom == NULL || cmvd == NULL)
4564 goto invalid_compression;
4566 method = QT_FOURCC ((guint8 *) dcom->data + 8);
4569 case GST_MAKE_FOURCC ('z', 'l', 'i', 'b'):{
4570 guint uncompressed_length;
4571 guint compressed_length;
4574 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
4575 compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12;
4576 GST_LOG ("length = %u", uncompressed_length);
4579 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
4580 compressed_length, uncompressed_length);
4582 qtdemux->moov_node_compressed = qtdemux->moov_node;
4583 qtdemux->moov_node = g_node_new (buf);
4585 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
4586 uncompressed_length);
4589 #endif /* HAVE_ZLIB */
4591 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
4592 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
4599 invalid_compression:
4601 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
4607 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
4610 while (G_UNLIKELY (buf < end)) {
4614 if (G_UNLIKELY (buf + 4 > end)) {
4615 GST_LOG_OBJECT (qtdemux, "buffer overrun");
4618 len = QT_UINT32 (buf);
4619 if (G_UNLIKELY (len == 0)) {
4620 GST_LOG_OBJECT (qtdemux, "empty container");
4623 if (G_UNLIKELY (len < 8)) {
4624 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
4627 if (G_UNLIKELY (len > (end - buf))) {
4628 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
4629 (gint) (end - buf));
4633 child = g_node_new ((guint8 *) buf);
4634 g_node_append (node, child);
4635 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
4636 qtdemux_parse_node (qtdemux, child, buf, len);
4644 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
4647 int len = QT_UINT32 (xdxt->data);
4648 guint8 *buf = xdxt->data;
4649 guint8 *end = buf + len;
4652 /* skip size and type */
4660 size = QT_UINT32 (buf);
4661 type = QT_FOURCC (buf + 4);
4663 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
4665 if (buf + size > end || size <= 0)
4671 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
4672 GST_FOURCC_ARGS (type));
4676 buffer = gst_buffer_new_and_alloc (size);
4677 _gst_buffer_copy_into_mem (buffer, 0, buf, size);
4678 stream->buffers = g_slist_append (stream->buffers, buffer);
4679 GST_LOG_OBJECT (qtdemux, "parsing theora header");
4682 buffer = gst_buffer_new_and_alloc (size);
4683 _gst_buffer_copy_into_mem (buffer, 0, buf, size);
4684 stream->buffers = g_slist_append (stream->buffers, buffer);
4685 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
4688 buffer = gst_buffer_new_and_alloc (size);
4689 _gst_buffer_copy_into_mem (buffer, 0, buf, size);
4690 stream->buffers = g_slist_append (stream->buffers, buffer);
4691 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
4694 GST_WARNING_OBJECT (qtdemux,
4695 "unknown theora cookie %" GST_FOURCC_FORMAT,
4696 GST_FOURCC_ARGS (type));
4705 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
4709 guint32 node_length = 0;
4710 const QtNodeType *type;
4713 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
4715 if (G_UNLIKELY (length < 8))
4716 goto not_enough_data;
4718 node_length = QT_UINT32 (buffer);
4719 fourcc = QT_FOURCC (buffer + 4);
4721 /* ignore empty nodes */
4722 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
4725 type = qtdemux_type_get (fourcc);
4727 end = buffer + length;
4729 GST_LOG_OBJECT (qtdemux,
4730 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
4731 GST_FOURCC_ARGS (fourcc), node_length, type->name);
4733 if (node_length > length)
4734 goto broken_atom_size;
4736 if (type->flags & QT_FLAG_CONTAINER) {
4737 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
4742 if (node_length < 20) {
4743 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
4746 GST_DEBUG_OBJECT (qtdemux,
4747 "parsing stsd (sample table, sample description) atom");
4748 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
4758 /* also read alac (or whatever) in stead of mp4a in the following,
4759 * since a similar layout is used in other cases as well */
4760 if (fourcc == FOURCC_mp4a)
4765 /* There are two things we might encounter here: a true mp4a atom, and
4766 an mp4a entry in an stsd atom. The latter is what we're interested
4767 in, and it looks like an atom, but isn't really one. The true mp4a
4768 atom is short, so we detect it based on length here. */
4769 if (length < min_size) {
4770 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
4771 GST_FOURCC_ARGS (fourcc));
4775 /* 'version' here is the sound sample description version. Types 0 and
4776 1 are documented in the QTFF reference, but type 2 is not: it's
4777 described in Apple header files instead (struct SoundDescriptionV2
4779 version = QT_UINT16 (buffer + 16);
4781 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
4782 GST_FOURCC_ARGS (fourcc), version);
4784 /* parse any esds descriptors */
4796 GST_WARNING_OBJECT (qtdemux,
4797 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
4798 GST_FOURCC_ARGS (fourcc), version);
4803 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
4815 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
4816 GST_FOURCC_ARGS (fourcc));
4817 version = QT_UINT32 (buffer + 16);
4818 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
4819 if (1 || version == 0x00000000) {
4820 buf = buffer + 0x32;
4822 /* FIXME Quicktime uses PASCAL string while
4823 * the iso format uses C strings. Check the file
4824 * type before attempting to parse the string here. */
4825 tlen = QT_UINT8 (buf);
4826 GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
4828 GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
4829 /* the string has a reserved space of 32 bytes so skip
4830 * the remaining 31 */
4832 buf += 4; /* and 4 bytes reserved */
4834 GST_MEMDUMP_OBJECT (qtdemux, "mp4v", buf, end - buf);
4836 qtdemux_parse_container (qtdemux, node, buf, end);
4842 GST_MEMDUMP_OBJECT (qtdemux, "avc1", buffer, end - buffer);
4843 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
4848 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
4853 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
4854 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
4862 version = QT_UINT32 (buffer + 12);
4863 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
4870 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
4875 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
4880 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
4884 if (!strcmp (type->name, "unknown"))
4885 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
4889 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
4890 GST_FOURCC_ARGS (fourcc));
4896 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4897 (_("This file is corrupt and cannot be played.")),
4898 ("Not enough data for an atom header, got only %u bytes", length));
4903 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4904 (_("This file is corrupt and cannot be played.")),
4905 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
4906 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
4913 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
4917 guint32 child_fourcc;
4919 for (child = g_node_first_child (node); child;
4920 child = g_node_next_sibling (child)) {
4921 buffer = (guint8 *) child->data;
4923 child_fourcc = QT_FOURCC (buffer + 4);
4925 if (G_UNLIKELY (child_fourcc == fourcc)) {
4933 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
4934 GstByteReader * parser)
4938 guint32 child_fourcc, child_len;
4940 for (child = g_node_first_child (node); child;
4941 child = g_node_next_sibling (child)) {
4942 buffer = (guint8 *) child->data;
4944 child_len = QT_UINT32 (buffer);
4945 child_fourcc = QT_FOURCC (buffer + 4);
4947 if (G_UNLIKELY (child_fourcc == fourcc)) {
4948 if (G_UNLIKELY (child_len < (4 + 4)))
4950 /* FIXME: must verify if atom length < parent atom length */
4951 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
4959 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
4960 GstByteReader * parser)
4964 guint32 child_fourcc, child_len;
4966 for (child = g_node_next_sibling (node); child;
4967 child = g_node_next_sibling (child)) {
4968 buffer = (guint8 *) child->data;
4970 child_fourcc = QT_FOURCC (buffer + 4);
4972 if (child_fourcc == fourcc) {
4974 child_len = QT_UINT32 (buffer);
4975 if (G_UNLIKELY (child_len < (4 + 4)))
4977 /* FIXME: must verify if atom length < parent atom length */
4978 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
4987 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
4989 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
4993 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
4994 QtDemuxStream * stream, GstTagList * list)
4996 /* consistent default for push based mode */
4997 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
4999 if (stream->subtype == FOURCC_vide) {
5000 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
5003 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
5006 /* fps is calculated base on the duration of the first frames since
5007 * qt does not have a fixed framerate. */
5008 if ((stream->n_samples == 1) && (stream->min_duration == 0)) {
5013 stream->fps_n = stream->timescale;
5014 if (stream->min_duration == 0)
5017 stream->fps_d = stream->min_duration;
5022 gint depth, palette_count;
5023 const guint32 *palette_data = NULL;
5025 gst_caps_set_simple (stream->caps,
5026 "width", G_TYPE_INT, stream->width,
5027 "height", G_TYPE_INT, stream->height,
5028 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
5030 /* calculate pixel-aspect-ratio using display width and height */
5031 GST_DEBUG_OBJECT (qtdemux,
5032 "video size %dx%d, target display size %dx%d", stream->width,
5033 stream->height, stream->display_width, stream->display_height);
5035 if (stream->display_width > 0 && stream->display_height > 0 &&
5036 stream->width > 0 && stream->height > 0) {
5039 /* calculate the pixel aspect ratio using the display and pixel w/h */
5040 n = stream->display_width * stream->height;
5041 d = stream->display_height * stream->width;
5044 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
5045 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
5046 GST_TYPE_FRACTION, n, d, NULL);
5049 /* qt file might have pasp atom */
5050 if (stream->par_w > 0 && stream->par_h > 0) {
5051 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
5052 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
5053 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
5056 depth = stream->bits_per_sample;
5058 /* more than 32 bits means grayscale */
5059 gray = (depth > 32);
5060 /* low 32 bits specify the depth */
5063 /* different number of palette entries is determined by depth. */
5065 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
5066 palette_count = (1 << depth);
5068 switch (palette_count) {
5072 palette_data = ff_qt_default_palette_2;
5075 palette_data = ff_qt_default_palette_4;
5079 palette_data = ff_qt_grayscale_palette_16;
5081 palette_data = ff_qt_default_palette_16;
5085 palette_data = ff_qt_grayscale_palette_256;
5087 palette_data = ff_qt_default_palette_256;
5090 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
5091 (_("The video in this file might not play correctly.")),
5092 ("unsupported palette depth %d", depth));
5098 /* make sure it's not writable. We leave MALLOCDATA to NULL so that we
5099 * don't free any of the buffer data. */
5100 palette = _gst_buffer_new_wrapped ((gpointer) palette_data,
5101 palette_count, NULL);
5103 gst_caps_set_simple (stream->caps, "palette_data",
5104 GST_TYPE_BUFFER, palette, NULL);
5105 gst_buffer_unref (palette);
5106 } else if (palette_count != 0) {
5107 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
5108 (NULL), ("Unsupported palette depth %d. Ignoring stream.", depth));
5110 gst_object_unref (stream->pad);
5114 qtdemux->n_video_streams++;
5115 } else if (stream->subtype == FOURCC_soun) {
5116 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
5119 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
5122 /* FIXME: Need to set channel-mask here and maybe reorder */
5123 gst_caps_set_simple (stream->caps,
5124 "rate", G_TYPE_INT, (int) stream->rate,
5125 "channels", G_TYPE_INT, stream->n_channels, NULL);
5127 qtdemux->n_audio_streams++;
5128 } else if (stream->subtype == FOURCC_strm) {
5129 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
5130 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text) {
5131 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
5134 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
5136 qtdemux->n_sub_streams++;
5138 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5143 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
5145 gst_pad_use_fixed_caps (stream->pad);
5146 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
5147 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
5148 gst_pad_set_active (stream->pad, TRUE);
5150 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
5151 gst_pad_set_caps (stream->pad, stream->caps);
5153 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
5154 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
5155 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
5157 if (stream->pending_tags)
5158 gst_tag_list_free (stream->pending_tags);
5159 stream->pending_tags = list;
5160 /* global tags go on each pad anyway */
5161 stream->send_global_tags = TRUE;
5167 /* find next atom with @fourcc starting at @offset */
5168 static GstFlowReturn
5169 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
5170 guint64 * length, guint32 fourcc)
5176 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
5177 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
5182 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
5183 if (G_UNLIKELY (ret != GST_FLOW_OK))
5185 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
5188 gst_buffer_unref (buf);
5191 gst_buffer_map (buf, &map, GST_MAP_READ);
5192 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
5193 gst_buffer_unmap (buf, &map);
5194 gst_buffer_unref (buf);
5196 if (G_UNLIKELY (*length == 0)) {
5197 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
5198 ret = GST_FLOW_ERROR;
5202 if (lfourcc == fourcc) {
5203 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
5207 GST_LOG_OBJECT (qtdemux,
5208 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
5209 GST_FOURCC_ARGS (fourcc), *offset);
5218 /* might simply have had last one */
5219 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
5224 /* should only do something in pull mode */
5225 /* call with OBJECT lock */
5226 static GstFlowReturn
5227 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
5229 guint64 length, offset;
5230 GstBuffer *buf = NULL;
5231 GstFlowReturn ret = GST_FLOW_OK;
5232 GstFlowReturn res = GST_FLOW_OK;
5235 offset = qtdemux->moof_offset;
5236 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
5239 GST_DEBUG_OBJECT (qtdemux, "no next moof");
5240 return GST_FLOW_EOS;
5243 /* best not do pull etc with lock held */
5244 GST_OBJECT_UNLOCK (qtdemux);
5246 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
5247 if (ret != GST_FLOW_OK)
5250 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
5251 if (G_UNLIKELY (ret != GST_FLOW_OK))
5253 gst_buffer_map (buf, &map, GST_MAP_READ);
5254 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
5255 gst_buffer_unmap (buf, &map);
5256 gst_buffer_unref (buf);
5261 gst_buffer_unmap (buf, &map);
5262 gst_buffer_unref (buf);
5266 /* look for next moof */
5267 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
5268 if (G_UNLIKELY (ret != GST_FLOW_OK))
5272 GST_OBJECT_LOCK (qtdemux);
5274 qtdemux->moof_offset = offset;
5280 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
5282 res = GST_FLOW_ERROR;
5287 /* maybe upstream temporarily flushing */
5288 if (ret != GST_FLOW_FLUSHING) {
5289 GST_DEBUG_OBJECT (qtdemux, "no next moof");
5292 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
5293 /* resume at current position next time */
5300 /* initialise bytereaders for stbl sub-atoms */
5302 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
5304 stream->stbl_index = -1; /* no samples have yet been parsed */
5306 /* time-to-sample atom */
5307 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
5310 /* copy atom data into a new buffer for later use */
5311 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
5313 /* skip version + flags */
5314 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
5315 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
5317 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
5319 /* make sure there's enough data */
5320 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
5321 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
5322 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
5323 stream->n_sample_times);
5324 if (!stream->n_sample_times)
5328 /* sync sample atom */
5329 stream->stps_present = FALSE;
5330 if ((stream->stss_present =
5331 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
5332 &stream->stss) ? TRUE : FALSE) == TRUE) {
5333 /* copy atom data into a new buffer for later use */
5334 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
5336 /* skip version + flags */
5337 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
5338 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
5341 if (stream->n_sample_syncs) {
5342 /* make sure there's enough data */
5343 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
5347 /* partial sync sample atom */
5348 if ((stream->stps_present =
5349 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
5350 &stream->stps) ? TRUE : FALSE) == TRUE) {
5351 /* copy atom data into a new buffer for later use */
5352 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
5354 /* skip version + flags */
5355 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
5356 !gst_byte_reader_get_uint32_be (&stream->stps,
5357 &stream->n_sample_partial_syncs))
5360 /* if there are no entries, the stss table contains the real
5362 if (stream->n_sample_partial_syncs) {
5363 /* make sure there's enough data */
5364 if (!qt_atom_parser_has_chunks (&stream->stps,
5365 stream->n_sample_partial_syncs, 4))
5372 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
5375 /* copy atom data into a new buffer for later use */
5376 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
5378 /* skip version + flags */
5379 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
5380 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
5383 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
5386 if (!stream->n_samples)
5389 /* sample-to-chunk atom */
5390 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
5393 /* copy atom data into a new buffer for later use */
5394 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
5396 /* skip version + flags */
5397 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
5398 !gst_byte_reader_get_uint32_be (&stream->stsc,
5399 &stream->n_samples_per_chunk))
5402 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
5403 stream->n_samples_per_chunk);
5405 /* make sure there's enough data */
5406 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
5412 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
5413 stream->co_size = sizeof (guint32);
5414 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
5416 stream->co_size = sizeof (guint64);
5420 /* copy atom data into a new buffer for later use */
5421 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
5423 /* skip version + flags */
5424 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
5427 /* chunks_are_chunks == 0 means treat chunks as samples */
5428 stream->chunks_are_chunks = !stream->sample_size || stream->sampled;
5429 if (stream->chunks_are_chunks) {
5430 /* skip number of entries */
5431 if (!gst_byte_reader_skip (&stream->stco, 4))
5434 /* make sure there are enough data in the stsz atom */
5435 if (!stream->sample_size) {
5436 /* different sizes for each sample */
5437 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
5441 /* treat chunks as samples */
5442 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
5446 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
5447 stream->n_samples, (guint) sizeof (QtDemuxSample),
5448 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
5450 if (stream->n_samples >=
5451 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
5452 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
5453 "be larger than %uMB (broken file?)", stream->n_samples,
5454 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
5458 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
5459 if (!stream->samples) {
5460 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
5466 /* composition time-to-sample */
5467 if ((stream->ctts_present =
5468 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
5469 &stream->ctts) ? TRUE : FALSE) == TRUE) {
5470 /* copy atom data into a new buffer for later use */
5471 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
5473 /* skip version + flags */
5474 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
5475 || !gst_byte_reader_get_uint32_be (&stream->ctts,
5476 &stream->n_composition_times))
5479 /* make sure there's enough data */
5480 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
5489 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5490 (_("This file is corrupt and cannot be played.")), (NULL));
5495 gst_qtdemux_stbl_free (stream);
5496 if (!qtdemux->fragmented) {
5497 /* not quite good */
5498 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
5501 /* may pick up samples elsewhere */
5507 /* collect samples from the next sample to be parsed up to sample @n for @stream
5508 * by reading the info from @stbl
5510 * This code can be executed from both the streaming thread and the seeking
5511 * thread so it takes the object lock to protect itself
5514 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
5517 QtDemuxSample *samples, *first, *cur, *last;
5518 guint32 n_samples_per_chunk;
5521 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
5522 GST_FOURCC_FORMAT ", pad %s", GST_FOURCC_ARGS (stream->fourcc),
5523 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
5525 n_samples = stream->n_samples;
5528 goto out_of_samples;
5530 GST_OBJECT_LOCK (qtdemux);
5531 if (n <= stream->stbl_index)
5532 goto already_parsed;
5534 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
5536 if (!stream->stsz.data) {
5537 /* so we already parsed and passed all the moov samples;
5538 * onto fragmented ones */
5539 g_assert (qtdemux->fragmented);
5543 /* pointer to the sample table */
5544 samples = stream->samples;
5546 /* starts from -1, moves to the next sample index to parse */
5547 stream->stbl_index++;
5549 /* keep track of the first and last sample to fill */
5550 first = &samples[stream->stbl_index];
5553 if (stream->chunks_are_chunks) {
5554 /* set the sample sizes */
5555 if (stream->sample_size == 0) {
5556 /* different sizes for each sample */
5557 for (cur = first; cur <= last; cur++) {
5558 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
5559 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
5560 (guint) (cur - samples), cur->size);
5563 /* samples have the same size */
5564 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
5565 for (cur = first; cur <= last; cur++)
5566 cur->size = stream->sample_size;
5570 n_samples_per_chunk = stream->n_samples_per_chunk;
5573 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
5576 if (stream->stsc_chunk_index >= stream->last_chunk
5577 || stream->stsc_chunk_index < stream->first_chunk) {
5578 stream->first_chunk =
5579 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
5580 stream->samples_per_chunk =
5581 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
5582 gst_byte_reader_skip_unchecked (&stream->stsc, 4);
5584 /* chunk numbers are counted from 1 it seems */
5585 if (G_UNLIKELY (stream->first_chunk == 0))
5588 --stream->first_chunk;
5590 /* the last chunk of each entry is calculated by taking the first chunk
5591 * of the next entry; except if there is no next, where we fake it with
5593 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
5594 stream->last_chunk = G_MAXUINT32;
5596 stream->last_chunk =
5597 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
5598 if (G_UNLIKELY (stream->last_chunk == 0))
5601 --stream->last_chunk;
5604 GST_LOG_OBJECT (qtdemux,
5605 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
5606 stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
5608 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
5611 if (stream->last_chunk != G_MAXUINT32) {
5612 if (!qt_atom_parser_peek_sub (&stream->stco,
5613 stream->first_chunk * stream->co_size,
5614 (stream->last_chunk - stream->first_chunk) * stream->co_size,
5619 stream->co_chunk = stream->stco;
5620 if (!gst_byte_reader_skip (&stream->co_chunk,
5621 stream->first_chunk * stream->co_size))
5625 stream->stsc_chunk_index = stream->first_chunk;
5628 last_chunk = stream->last_chunk;
5630 if (stream->chunks_are_chunks) {
5631 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
5632 guint32 samples_per_chunk;
5633 guint64 chunk_offset;
5635 if (!stream->stsc_sample_index
5636 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
5637 &stream->chunk_offset))
5640 samples_per_chunk = stream->samples_per_chunk;
5641 chunk_offset = stream->chunk_offset;
5643 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
5644 GST_LOG_OBJECT (qtdemux, "Creating entry %d with offset %"
5645 G_GUINT64_FORMAT, (guint) (cur - samples), stream->chunk_offset);
5647 cur->offset = chunk_offset;
5648 chunk_offset += cur->size;
5651 if (G_UNLIKELY (cur > last)) {
5653 stream->stsc_sample_index = k + 1;
5654 stream->chunk_offset = chunk_offset;
5655 stream->stsc_chunk_index = j;
5659 stream->stsc_sample_index = 0;
5661 stream->stsc_chunk_index = j;
5663 cur = &samples[stream->stsc_chunk_index];
5665 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
5668 stream->stsc_chunk_index = j;
5673 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
5676 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
5677 "%" G_GUINT64_FORMAT, j, cur->offset);
5679 if (stream->samples_per_frame * stream->bytes_per_frame) {
5681 (stream->samples_per_chunk * stream->n_channels) /
5682 stream->samples_per_frame * stream->bytes_per_frame;
5684 cur->size = stream->samples_per_chunk;
5687 GST_DEBUG_OBJECT (qtdemux,
5688 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
5689 j, GST_TIME_ARGS (gst_util_uint64_scale (stream->stco_sample_index,
5690 GST_SECOND, stream->timescale)), cur->size);
5692 cur->timestamp = stream->stco_sample_index;
5693 cur->duration = stream->samples_per_chunk;
5694 cur->keyframe = TRUE;
5697 stream->stco_sample_index += stream->samples_per_chunk;
5699 stream->stsc_chunk_index = j;
5701 stream->stsc_index++;
5704 if (!stream->chunks_are_chunks)
5708 guint32 n_sample_times;
5710 n_sample_times = stream->n_sample_times;
5713 for (i = stream->stts_index; i < n_sample_times; i++) {
5714 guint32 stts_samples;
5715 gint32 stts_duration;
5718 if (stream->stts_sample_index >= stream->stts_samples
5719 || !stream->stts_sample_index) {
5721 stream->stts_samples =
5722 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
5723 stream->stts_duration =
5724 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
5726 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
5727 i, stream->stts_samples, stream->stts_duration);
5729 stream->stts_sample_index = 0;
5732 stts_samples = stream->stts_samples;
5733 stts_duration = stream->stts_duration;
5734 stts_time = stream->stts_time;
5736 for (j = stream->stts_sample_index; j < stts_samples; j++) {
5737 GST_DEBUG_OBJECT (qtdemux,
5738 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
5739 (guint) (cur - samples), j,
5740 GST_TIME_ARGS (gst_util_uint64_scale (stts_time, GST_SECOND,
5741 stream->timescale)));
5743 cur->timestamp = stts_time;
5744 cur->duration = stts_duration;
5746 /* avoid 32-bit wrap-around,
5747 * but still mind possible 'negative' duration */
5748 stts_time += (gint64) stts_duration;
5751 if (G_UNLIKELY (cur > last)) {
5753 stream->stts_time = stts_time;
5754 stream->stts_sample_index = j + 1;
5758 stream->stts_sample_index = 0;
5759 stream->stts_time = stts_time;
5760 stream->stts_index++;
5762 /* fill up empty timestamps with the last timestamp, this can happen when
5763 * the last samples do not decode and so we don't have timestamps for them.
5764 * We however look at the last timestamp to estimate the track length so we
5765 * need something in here. */
5766 for (; cur < last; cur++) {
5767 GST_DEBUG_OBJECT (qtdemux,
5768 "fill sample %d: timestamp %" GST_TIME_FORMAT,
5769 (guint) (cur - samples),
5770 GST_TIME_ARGS (gst_util_uint64_scale (stream->stts_time, GST_SECOND,
5771 stream->timescale)));
5772 cur->timestamp = stream->stts_time;
5778 /* sample sync, can be NULL */
5779 if (stream->stss_present == TRUE) {
5780 guint32 n_sample_syncs;
5782 n_sample_syncs = stream->n_sample_syncs;
5784 if (!n_sample_syncs) {
5785 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
5786 stream->all_keyframe = TRUE;
5788 for (i = stream->stss_index; i < n_sample_syncs; i++) {
5789 /* note that the first sample is index 1, not 0 */
5792 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
5794 if (G_LIKELY (index > 0 && index <= n_samples)) {
5796 samples[index].keyframe = TRUE;
5797 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
5798 /* and exit if we have enough samples */
5799 if (G_UNLIKELY (index >= n)) {
5806 stream->stss_index = i;
5809 /* stps marks partial sync frames like open GOP I-Frames */
5810 if (stream->stps_present == TRUE) {
5811 guint32 n_sample_partial_syncs;
5813 n_sample_partial_syncs = stream->n_sample_partial_syncs;
5815 /* if there are no entries, the stss table contains the real
5817 if (n_sample_partial_syncs) {
5818 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
5819 /* note that the first sample is index 1, not 0 */
5822 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
5824 if (G_LIKELY (index > 0 && index <= n_samples)) {
5826 samples[index].keyframe = TRUE;
5827 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
5828 /* and exit if we have enough samples */
5829 if (G_UNLIKELY (index >= n)) {
5836 stream->stps_index = i;
5840 /* no stss, all samples are keyframes */
5841 stream->all_keyframe = TRUE;
5842 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
5847 /* composition time to sample */
5848 if (stream->ctts_present == TRUE) {
5849 guint32 n_composition_times;
5851 gint32 ctts_soffset;
5853 /* Fill in the pts_offsets */
5855 n_composition_times = stream->n_composition_times;
5857 for (i = stream->ctts_index; i < n_composition_times; i++) {
5858 if (stream->ctts_sample_index >= stream->ctts_count
5859 || !stream->ctts_sample_index) {
5860 stream->ctts_count =
5861 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
5862 stream->ctts_soffset =
5863 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
5864 stream->ctts_sample_index = 0;
5867 ctts_count = stream->ctts_count;
5868 ctts_soffset = stream->ctts_soffset;
5870 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
5871 cur->pts_offset = ctts_soffset;
5874 if (G_UNLIKELY (cur > last)) {
5876 stream->ctts_sample_index = j + 1;
5880 stream->ctts_sample_index = 0;
5881 stream->ctts_index++;
5885 stream->stbl_index = n;
5886 /* if index has been completely parsed, free data that is no-longer needed */
5887 if (n + 1 == stream->n_samples) {
5888 gst_qtdemux_stbl_free (stream);
5889 GST_DEBUG_OBJECT (qtdemux,
5890 "parsed all available samples; checking for more");
5891 while (n + 1 == stream->n_samples)
5892 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
5895 GST_OBJECT_UNLOCK (qtdemux);
5902 GST_LOG_OBJECT (qtdemux,
5903 "Tried to parse up to sample %u but this sample has already been parsed",
5905 /* if fragmented, there may be more */
5906 if (qtdemux->fragmented && n == stream->stbl_index)
5908 GST_OBJECT_UNLOCK (qtdemux);
5914 GST_LOG_OBJECT (qtdemux,
5915 "Tried to parse up to sample %u but there are only %u samples", n + 1,
5917 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5918 (_("This file is corrupt and cannot be played.")), (NULL));
5923 GST_OBJECT_UNLOCK (qtdemux);
5924 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5925 (_("This file is corrupt and cannot be played.")), (NULL));
5930 /* collect all segment info for @stream.
5933 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
5938 /* parse and prepare segment info from the edit list */
5939 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
5940 stream->n_segments = 0;
5941 stream->segments = NULL;
5942 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
5946 guint64 time, stime;
5949 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
5950 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
5953 buffer = elst->data;
5955 n_segments = QT_UINT32 (buffer + 12);
5957 /* we might allocate a bit too much, at least allocate 1 segment */
5958 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
5960 /* segments always start from 0 */
5964 for (i = 0; i < n_segments; i++) {
5967 QtDemuxSegment *segment;
5970 media_time = QT_UINT32 (buffer + 20 + i * 12);
5972 /* -1 media time is an empty segment, just ignore it */
5973 if (media_time == G_MAXUINT32)
5976 duration = QT_UINT32 (buffer + 16 + i * 12);
5978 segment = &stream->segments[count++];
5980 /* time and duration expressed in global timescale */
5981 segment->time = stime;
5982 /* add non scaled values so we don't cause roundoff errors */
5984 stime = gst_util_uint64_scale (time, GST_SECOND, qtdemux->timescale);
5985 segment->stop_time = stime;
5986 segment->duration = stime - segment->time;
5987 /* media_time expressed in stream timescale */
5988 segment->media_start =
5989 gst_util_uint64_scale (media_time, GST_SECOND, stream->timescale);
5990 segment->media_stop = segment->media_start + segment->duration;
5991 rate_int = GST_READ_UINT32_BE (buffer + 24 + i * 12);
5993 if (rate_int <= 1) {
5994 /* 0 is not allowed, some programs write 1 instead of the floating point
5996 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
6000 segment->rate = rate_int / 65536.0;
6003 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
6004 ", duration %" GST_TIME_FORMAT ", media_time %" GST_TIME_FORMAT
6005 ", rate %g, (%d)", i, GST_TIME_ARGS (segment->time),
6006 GST_TIME_ARGS (segment->duration),
6007 GST_TIME_ARGS (segment->media_start), segment->rate, rate_int);
6009 GST_DEBUG_OBJECT (qtdemux, "found %d non-empty segments", count);
6010 stream->n_segments = count;
6014 /* push based does not handle segments, so act accordingly here,
6015 * and warn if applicable */
6016 if (!qtdemux->pullbased) {
6017 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
6018 /* remove and use default one below, we stream like it anyway */
6019 g_free (stream->segments);
6020 stream->segments = NULL;
6021 stream->n_segments = 0;
6024 /* no segments, create one to play the complete trak */
6025 if (stream->n_segments == 0) {
6026 GstClockTime stream_duration =
6027 gst_util_uint64_scale (stream->duration, GST_SECOND, stream->timescale);
6029 if (stream->segments == NULL)
6030 stream->segments = g_new (QtDemuxSegment, 1);
6032 /* represent unknown our way */
6033 if (stream_duration == 0)
6034 stream_duration = -1;
6036 stream->segments[0].time = 0;
6037 stream->segments[0].stop_time = stream_duration;
6038 stream->segments[0].duration = stream_duration;
6039 stream->segments[0].media_start = 0;
6040 stream->segments[0].media_stop = stream_duration;
6041 stream->segments[0].rate = 1.0;
6043 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
6044 GST_TIME_ARGS (stream_duration));
6045 stream->n_segments = 1;
6047 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
6053 * Parses the stsd atom of a svq3 trak looking for
6054 * the SMI and gama atoms.
6057 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
6058 guint8 ** gamma, GstBuffer ** seqh)
6060 guint8 *_gamma = NULL;
6061 GstBuffer *_seqh = NULL;
6062 guint8 *stsd_data = stsd->data;
6063 guint32 length = QT_UINT32 (stsd_data);
6067 GST_WARNING_OBJECT (qtdemux, "stsd too short");
6073 version = QT_UINT16 (stsd_data);
6078 while (length > 8) {
6079 guint32 fourcc, size;
6081 size = QT_UINT32 (stsd_data);
6082 fourcc = QT_FOURCC (stsd_data + 4);
6083 data = stsd_data + 8;
6090 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
6091 " for gama atom, expected 12", size);
6096 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
6098 if (_seqh != NULL) {
6099 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
6100 " found, ignoring");
6102 seqh_size = QT_UINT32 (data + 4);
6103 if (seqh_size > 0) {
6104 _seqh = gst_buffer_new_and_alloc (seqh_size);
6105 _gst_buffer_copy_into_mem (_seqh, 0, data + 8, seqh_size);
6112 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
6113 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
6117 if (size <= length) {
6123 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
6126 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
6127 G_GUINT16_FORMAT, version);
6138 gst_buffer_unref (_seqh);
6143 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
6150 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
6151 * atom that might contain a 'data' atom with the rtsp uri.
6152 * This case was reported in bug #597497, some info about
6153 * the hndl atom can be found in TN1195
6155 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
6156 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
6159 guint32 dref_num_entries = 0;
6160 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
6161 gst_byte_reader_skip (&dref, 4) &&
6162 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
6165 /* search dref entries for hndl atom */
6166 for (i = 0; i < dref_num_entries; i++) {
6167 guint32 size = 0, type;
6168 guint8 string_len = 0;
6169 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
6170 qt_atom_parser_get_fourcc (&dref, &type)) {
6171 if (type == FOURCC_hndl) {
6172 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
6174 /* skip data reference handle bytes and the
6175 * following pascal string and some extra 4
6176 * bytes I have no idea what are */
6177 if (!gst_byte_reader_skip (&dref, 4) ||
6178 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
6179 !gst_byte_reader_skip (&dref, string_len + 4)) {
6180 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
6184 /* iterate over the atoms to find the data atom */
6185 while (gst_byte_reader_get_remaining (&dref) >= 8) {
6189 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
6190 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
6191 if (atom_type == FOURCC_data) {
6192 const guint8 *uri_aux = NULL;
6194 /* found the data atom that might contain the rtsp uri */
6195 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
6196 "hndl atom, interpreting it as an URI");
6197 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
6199 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
6200 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
6202 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
6203 "didn't contain a rtsp address");
6205 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
6210 /* skipping to the next entry */
6211 gst_byte_reader_skip (&dref, atom_size - 8);
6213 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
6220 /* skip to the next entry */
6221 gst_byte_reader_skip (&dref, size - 8);
6223 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
6226 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
6233 less_than (gconstpointer a, gconstpointer b)
6235 const guint32 *av = a, *bv = b;
6240 #define AMR_NB_ALL_MODES 0x81ff
6241 #define AMR_WB_ALL_MODES 0x83ff
6243 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
6245 /* The 'damr' atom is of the form:
6247 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
6248 * 32 b 8 b 16 b 8 b 8 b
6250 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
6251 * represents the highest mode used in the stream (and thus the maximum
6252 * bitrate), with a couple of special cases as seen below.
6255 /* Map of frame type ID -> bitrate */
6256 static const guint nb_bitrates[] = {
6257 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
6259 static const guint wb_bitrates[] = {
6260 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
6266 gst_buffer_map (buf, &map, GST_MAP_READ);
6268 if (map.size != 0x11) {
6269 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
6273 if (QT_FOURCC (map.data + 4) != GST_MAKE_FOURCC ('d', 'a', 'm', 'r')) {
6274 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
6275 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
6279 mode_set = QT_UINT16 (map.data + 13);
6281 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
6282 max_mode = 7 + (wb ? 1 : 0);
6284 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
6285 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
6287 if (max_mode == -1) {
6288 GST_DEBUG ("No mode indication was found (mode set) = %x",
6293 gst_buffer_unmap (buf, &map);
6294 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
6297 gst_buffer_unmap (buf, &map);
6302 * With each track we associate a new QtDemuxStream that contains all the info
6304 * traks that do not decode to something (like strm traks) will not have a pad.
6307 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
6322 QtDemuxStream *stream;
6323 GstTagList *list = NULL;
6324 gchar *codec = NULL;
6325 const guint8 *stsd_data;
6326 guint16 lang_code; /* quicktime lang code or packed iso code */
6328 guint32 tkhd_flags = 0;
6329 guint8 tkhd_version = 0;
6331 guint value_size, len;
6333 stream = g_new0 (QtDemuxStream, 1);
6334 /* new streams always need a discont */
6335 stream->discont = TRUE;
6336 /* we enable clipping for raw audio/video streams */
6337 stream->need_clip = FALSE;
6338 stream->need_process = FALSE;
6339 stream->segment_index = -1;
6340 stream->time_position = 0;
6341 stream->sample_index = -1;
6342 stream->last_ret = GST_FLOW_OK;
6344 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
6345 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
6346 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
6349 /* pick between 64 or 32 bits */
6350 value_size = tkhd_version == 1 ? 8 : 4;
6351 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
6352 !gst_byte_reader_get_uint32_be (&tkhd, &stream->track_id))
6355 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
6356 tkhd_version, tkhd_flags, stream->track_id);
6358 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
6361 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
6362 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
6363 if (qtdemux->major_brand != FOURCC_mjp2 ||
6364 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
6368 len = QT_UINT32 ((guint8 *) mdhd->data);
6369 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
6370 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
6371 if (version == 0x01000000) {
6374 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
6375 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
6376 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
6380 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
6381 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
6382 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
6385 if (lang_code < 0x800) {
6386 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
6388 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
6389 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
6390 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
6391 stream->lang_id[3] = 0;
6394 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
6396 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
6398 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
6399 lang_code, stream->lang_id);
6401 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
6404 /* fragmented files may have bogus duration in moov */
6405 if (!qtdemux->fragmented &&
6406 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
6407 guint64 tdur1, tdur2;
6409 /* don't overflow */
6410 tdur1 = stream->timescale * (guint64) qtdemux->duration;
6411 tdur2 = qtdemux->timescale * (guint64) stream->duration;
6414 * some of those trailers, nowadays, have prologue images that are
6415 * themselves vide tracks as well. I haven't really found a way to
6416 * identify those yet, except for just looking at their duration. */
6417 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
6418 GST_WARNING_OBJECT (qtdemux,
6419 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
6420 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
6421 "found, assuming preview image or something; skipping track",
6422 stream->duration, stream->timescale, qtdemux->duration,
6423 qtdemux->timescale);
6429 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
6432 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
6433 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
6435 len = QT_UINT32 ((guint8 *) hdlr->data);
6437 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
6438 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
6439 GST_FOURCC_ARGS (stream->subtype));
6441 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
6444 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
6448 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
6450 stsd_data = (const guint8 *) stsd->data;
6452 /* stsd should at least have one entry */
6453 len = QT_UINT32 (stsd_data);
6457 /* and that entry should fit within stsd */
6458 len = QT_UINT32 (stsd_data + 16);
6459 if (len > QT_UINT32 (stsd_data) + 16)
6461 GST_LOG_OBJECT (qtdemux, "stsd len: %d", len);
6463 stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
6464 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
6465 GST_FOURCC_ARGS (stream->fourcc));
6467 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi) ||
6468 ((fourcc & 0xFFFFFF00) == GST_MAKE_FOURCC ('e', 'n', 'c', 0)))
6469 goto error_encrypted;
6471 if (stream->subtype == FOURCC_vide) {
6472 guint32 w = 0, h = 0;
6474 stream->sampled = TRUE;
6476 /* version 1 uses some 64-bit ints */
6477 if (!gst_byte_reader_skip (&tkhd, 56 + value_size)
6478 || !gst_byte_reader_get_uint32_be (&tkhd, &w)
6479 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
6482 stream->display_width = w >> 16;
6483 stream->display_height = h >> 16;
6489 stream->width = QT_UINT16 (stsd_data + offset + 32);
6490 stream->height = QT_UINT16 (stsd_data + offset + 34);
6491 stream->fps_n = 0; /* this is filled in later */
6492 stream->fps_d = 0; /* this is filled in later */
6493 stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
6494 stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
6496 GST_LOG_OBJECT (qtdemux, "frame count: %u",
6497 QT_UINT16 (stsd_data + offset + 48));
6500 qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
6502 list = gst_tag_list_new_empty ();
6503 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6504 GST_TAG_VIDEO_CODEC, codec, NULL);
6511 /* pick 'the' stsd child */
6512 mp4v = qtdemux_tree_get_child_by_type (stsd, fourcc);
6514 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
6515 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
6519 const guint8 *pasp_data = (const guint8 *) pasp->data;
6521 stream->par_w = QT_UINT32 (pasp_data + 8);
6522 stream->par_h = QT_UINT32 (pasp_data + 12);
6529 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
6534 gint len = QT_UINT32 (stsd_data) - 0x66;
6535 const guint8 *avc_data = stsd_data + 0x66;
6538 while (len >= 0x8) {
6541 if (QT_UINT32 (avc_data) <= len)
6542 size = QT_UINT32 (avc_data) - 0x8;
6547 /* No real data, so break out */
6550 switch (QT_FOURCC (avc_data + 0x4)) {
6553 /* parse, if found */
6556 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
6558 /* First 4 bytes are the length of the atom, the next 4 bytes
6559 * are the fourcc, the next 1 byte is the version, and the
6560 * subsequent bytes are sequence parameter set like data. */
6561 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
6562 avc_data + 8 + 1, size - 1);
6564 buf = gst_buffer_new_and_alloc (size);
6565 _gst_buffer_copy_into_mem (buf, 0, avc_data + 0x8, size);
6566 gst_caps_set_simple (stream->caps,
6567 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6568 gst_buffer_unref (buf);
6574 guint avg_bitrate, max_bitrate;
6576 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
6580 max_bitrate = QT_UINT32 (avc_data + 0xc);
6581 avg_bitrate = QT_UINT32 (avc_data + 0x10);
6583 if (!max_bitrate && !avg_bitrate)
6586 /* Some muxers seem to swap the average and maximum bitrates
6587 * (I'm looking at you, YouTube), so we swap for sanity. */
6588 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
6589 guint temp = avg_bitrate;
6591 avg_bitrate = max_bitrate;
6596 list = gst_tag_list_new_empty ();
6598 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
6599 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6600 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
6602 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
6603 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
6604 GST_TAG_BITRATE, avg_bitrate, NULL);
6615 avc_data += size + 8;
6627 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
6628 GST_FOURCC_ARGS (fourcc));
6630 /* codec data might be in glbl extension atom */
6632 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
6638 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
6640 len = QT_UINT32 (data);
6643 buf = gst_buffer_new_and_alloc (len);
6644 _gst_buffer_copy_into_mem (buf, 0, data + 8, len);
6645 gst_caps_set_simple (stream->caps,
6646 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6647 gst_buffer_unref (buf);
6654 /* see annex I of the jpeg2000 spec */
6655 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
6657 const gchar *colorspace = NULL;
6659 guint32 ncomp_map = 0;
6660 gint32 *comp_map = NULL;
6661 guint32 nchan_def = 0;
6662 gint32 *chan_def = NULL;
6664 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
6665 /* some required atoms */
6666 mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
6669 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
6673 /* number of components; redundant with info in codestream, but useful
6675 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
6676 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
6678 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
6680 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
6683 GST_DEBUG_OBJECT (qtdemux, "found colr");
6684 /* extract colour space info */
6685 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
6686 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
6688 colorspace = "sRGB";
6691 colorspace = "GRAY";
6694 colorspace = "sYUV";
6702 /* colr is required, and only values 16, 17, and 18 are specified,
6703 so error if we have no colorspace */
6706 /* extract component mapping */
6707 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
6709 guint32 cmap_len = 0;
6711 cmap_len = QT_UINT32 (cmap->data);
6712 if (cmap_len >= 8) {
6713 /* normal box, subtract off header */
6715 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
6716 if (cmap_len % 4 == 0) {
6717 ncomp_map = (cmap_len / 4);
6718 comp_map = g_new0 (gint32, ncomp_map);
6719 for (i = 0; i < ncomp_map; i++) {
6722 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
6723 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
6724 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
6725 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
6730 /* extract channel definitions */
6731 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
6733 guint32 cdef_len = 0;
6735 cdef_len = QT_UINT32 (cdef->data);
6736 if (cdef_len >= 10) {
6737 /* normal box, subtract off header and len */
6739 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
6740 if (cdef_len % 6 == 0) {
6741 nchan_def = (cdef_len / 6);
6742 chan_def = g_new0 (gint32, nchan_def);
6743 for (i = 0; i < nchan_def; i++)
6745 for (i = 0; i < nchan_def; i++) {
6746 guint16 cn, typ, asoc;
6747 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
6748 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
6749 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
6750 if (cn < nchan_def) {
6753 chan_def[cn] = asoc;
6756 chan_def[cn] = 0; /* alpha */
6759 chan_def[cn] = -typ;
6767 gst_caps_set_simple (stream->caps,
6768 "num-components", G_TYPE_INT, ncomp, NULL);
6769 gst_caps_set_simple (stream->caps,
6770 "colorspace", G_TYPE_STRING, colorspace, NULL);
6773 GValue arr = { 0, };
6774 GValue elt = { 0, };
6776 g_value_init (&arr, GST_TYPE_ARRAY);
6777 g_value_init (&elt, G_TYPE_INT);
6778 for (i = 0; i < ncomp_map; i++) {
6779 g_value_set_int (&elt, comp_map[i]);
6780 gst_value_array_append_value (&arr, &elt);
6782 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
6783 "component-map", &arr);
6784 g_value_unset (&elt);
6785 g_value_unset (&arr);
6790 GValue arr = { 0, };
6791 GValue elt = { 0, };
6793 g_value_init (&arr, GST_TYPE_ARRAY);
6794 g_value_init (&elt, G_TYPE_INT);
6795 for (i = 0; i < nchan_def; i++) {
6796 g_value_set_int (&elt, chan_def[i]);
6797 gst_value_array_append_value (&arr, &elt);
6799 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
6800 "channel-definitions", &arr);
6801 g_value_unset (&elt);
6802 g_value_unset (&arr);
6806 /* some optional atoms */
6807 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
6808 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
6810 /* indicate possible fields in caps */
6812 data = (guint8 *) field->data + 8;
6814 gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
6815 (gint) * data, NULL);
6817 /* add codec_data if provided */
6822 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
6823 data = prefix->data;
6824 len = QT_UINT32 (data);
6827 buf = gst_buffer_new_and_alloc (len);
6828 _gst_buffer_copy_into_mem (buf, 0, data + 8, len);
6829 gst_caps_set_simple (stream->caps,
6830 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6831 gst_buffer_unref (buf);
6840 GstBuffer *seqh = NULL;
6841 guint8 *gamma_data = NULL;
6842 gint len = QT_UINT32 (stsd_data);
6844 qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
6846 gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
6847 QT_FP32 (gamma_data), NULL);
6850 /* sorry for the bad name, but we don't know what this is, other
6851 * than its own fourcc */
6852 gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
6856 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
6857 buf = gst_buffer_new_and_alloc (len);
6858 _gst_buffer_copy_into_mem (buf, 0, stsd_data, len);
6859 gst_caps_set_simple (stream->caps,
6860 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6861 gst_buffer_unref (buf);
6866 gst_caps_set_simple (stream->caps,
6867 "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
6874 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
6875 xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
6879 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
6883 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
6884 /* collect the headers and store them in a stream list so that we can
6885 * send them out first */
6886 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
6896 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
6897 ovc1 = qtdemux_tree_get_child_by_type (stsd, FOURCC_ovc1);
6900 ovc1_data = ovc1->data;
6901 ovc1_len = QT_UINT32 (ovc1_data);
6902 if (ovc1_len <= 198) {
6903 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
6906 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
6907 _gst_buffer_copy_into_mem (buf, 0, ovc1_data + 198, ovc1_len - 198);
6908 gst_caps_set_simple (stream->caps,
6909 "codec_data", GST_TYPE_BUFFER, buf, NULL);
6910 gst_buffer_unref (buf);
6918 GST_INFO_OBJECT (qtdemux,
6919 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
6920 GST_FOURCC_ARGS (fourcc), stream->caps);
6922 } else if (stream->subtype == FOURCC_soun) {
6923 int version, samplesize;
6924 guint16 compression_id;
6925 gboolean amrwb = FALSE;
6931 version = QT_UINT32 (stsd_data + offset);
6932 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
6933 samplesize = QT_UINT16 (stsd_data + offset + 10);
6934 compression_id = QT_UINT16 (stsd_data + offset + 12);
6935 stream->rate = QT_FP32 (stsd_data + offset + 16);
6937 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
6938 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
6939 QT_UINT32 (stsd_data + offset + 4));
6940 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
6941 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
6942 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
6943 GST_LOG_OBJECT (qtdemux, "packet size: %d",
6944 QT_UINT16 (stsd_data + offset + 14));
6945 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
6947 if (compression_id == 0xfffe)
6948 stream->sampled = TRUE;
6950 /* first assume uncompressed audio */
6951 stream->bytes_per_sample = samplesize / 8;
6952 stream->samples_per_frame = stream->n_channels;
6953 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
6954 stream->samples_per_packet = stream->samples_per_frame;
6955 stream->bytes_per_packet = stream->bytes_per_sample;
6959 /* Yes, these have to be hard-coded */
6962 stream->samples_per_packet = 6;
6963 stream->bytes_per_packet = 1;
6964 stream->bytes_per_frame = 1 * stream->n_channels;
6965 stream->bytes_per_sample = 1;
6966 stream->samples_per_frame = 6 * stream->n_channels;
6971 stream->samples_per_packet = 3;
6972 stream->bytes_per_packet = 1;
6973 stream->bytes_per_frame = 1 * stream->n_channels;
6974 stream->bytes_per_sample = 1;
6975 stream->samples_per_frame = 3 * stream->n_channels;
6980 stream->samples_per_packet = 64;
6981 stream->bytes_per_packet = 34;
6982 stream->bytes_per_frame = 34 * stream->n_channels;
6983 stream->bytes_per_sample = 2;
6984 stream->samples_per_frame = 64 * stream->n_channels;
6990 stream->samples_per_packet = 1;
6991 stream->bytes_per_packet = 1;
6992 stream->bytes_per_frame = 1 * stream->n_channels;
6993 stream->bytes_per_sample = 1;
6994 stream->samples_per_frame = 1 * stream->n_channels;
6999 stream->samples_per_packet = 160;
7000 stream->bytes_per_packet = 33;
7001 stream->bytes_per_frame = 33 * stream->n_channels;
7002 stream->bytes_per_sample = 2;
7003 stream->samples_per_frame = 160 * stream->n_channels;
7010 if (version == 0x00010000) {
7018 /* only parse extra decoding config for non-pcm audio */
7019 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
7020 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
7021 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
7022 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
7024 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
7025 stream->samples_per_packet);
7026 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
7027 stream->bytes_per_packet);
7028 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
7029 stream->bytes_per_frame);
7030 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
7031 stream->bytes_per_sample);
7033 if (!stream->sampled && stream->bytes_per_packet) {
7034 stream->samples_per_frame = (stream->bytes_per_frame /
7035 stream->bytes_per_packet) * stream->samples_per_packet;
7036 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
7037 stream->samples_per_frame);
7042 } else if (version == 0x00020000) {
7049 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
7050 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
7051 stream->rate = qtfp.fp;
7052 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
7054 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
7055 stream->samples_per_packet);
7056 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
7057 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
7060 GST_WARNING_OBJECT (qtdemux, "unknown version %08x", version);
7063 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc, NULL, 0,
7072 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
7074 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
7076 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
7078 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
7081 gst_caps_set_simple (stream->caps,
7082 "format", G_TYPE_STRING, "S24_3LE", NULL);
7089 const guint8 *owma_data;
7090 const gchar *codec_name = NULL;
7094 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
7095 /* FIXME this should also be gst_riff_strf_auds,
7096 * but the latter one is actually missing bits-per-sample :( */
7101 gint32 nSamplesPerSec;
7102 gint32 nAvgBytesPerSec;
7104 gint16 wBitsPerSample;
7109 GST_DEBUG_OBJECT (qtdemux, "parse owma");
7110 owma = qtdemux_tree_get_child_by_type (stsd, FOURCC_owma);
7113 owma_data = owma->data;
7114 owma_len = QT_UINT32 (owma_data);
7115 if (owma_len <= 54) {
7116 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
7119 wfex = (WAVEFORMATEX *) (owma_data + 36);
7120 buf = gst_buffer_new_and_alloc (owma_len - 54);
7121 _gst_buffer_copy_into_mem (buf, 0, owma_data + 54, owma_len - 54);
7122 if (wfex->wFormatTag == 0x0161) {
7123 codec_name = "Windows Media Audio";
7125 } else if (wfex->wFormatTag == 0x0162) {
7126 codec_name = "Windows Media Audio 9 Pro";
7128 } else if (wfex->wFormatTag == 0x0163) {
7129 codec_name = "Windows Media Audio 9 Lossless";
7130 /* is that correct? gstffmpegcodecmap.c is missing it, but
7131 * fluendo codec seems to support it */
7135 gst_caps_set_simple (stream->caps,
7136 "codec_data", GST_TYPE_BUFFER, buf,
7137 "wmaversion", G_TYPE_INT, version,
7138 "block_align", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->nBlockAlign),
7139 "bitrate", G_TYPE_INT, GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec),
7140 "width", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
7141 "depth", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
7143 gst_buffer_unref (buf);
7147 codec = g_strdup (codec_name);
7159 list = gst_tag_list_new_empty ();
7160 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7161 GST_TAG_AUDIO_CODEC, codec, NULL);
7165 /* some bitrate info may have ended up in caps */
7166 s = gst_caps_get_structure (stream->caps, 0);
7167 gst_structure_get_int (s, "bitrate", &bitrate);
7169 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
7173 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
7177 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
7179 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
7181 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
7185 /* If the fourcc's bottom 16 bits gives 'sm', then the top
7186 16 bits is a byte-swapped wave-style codec identifier,
7187 and we can find a WAVE header internally to a 'wave' atom here.
7188 This can more clearly be thought of as 'ms' as the top 16 bits, and a
7189 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
7192 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
7193 if (len < offset + 20) {
7194 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
7196 guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
7197 const guint8 *data = stsd_data + offset + 16;
7199 GNode *waveheadernode;
7201 wavenode = g_node_new ((guint8 *) data);
7202 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
7203 const guint8 *waveheader;
7206 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
7207 if (waveheadernode) {
7208 waveheader = (const guint8 *) waveheadernode->data;
7209 headerlen = QT_UINT32 (waveheader);
7211 if (headerlen > 8) {
7212 gst_riff_strf_auds *header = NULL;
7213 GstBuffer *headerbuf;
7219 headerbuf = gst_buffer_new_and_alloc (headerlen);
7220 _gst_buffer_copy_into_mem (headerbuf, 0, waveheader, headerlen);
7222 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
7223 headerbuf, &header, &extra)) {
7224 gst_caps_unref (stream->caps);
7225 /* FIXME: Need to do something with the channel reorder map */
7226 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
7227 header, extra, NULL, NULL, NULL);
7230 gst_buffer_unref (extra);
7234 GST_DEBUG ("Didn't find waveheadernode for this codec");
7236 g_node_destroy (wavenode);
7239 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
7243 /* FIXME: what is in the chunk? */
7246 gint len = QT_UINT32 (stsd_data);
7248 /* seems to be always = 116 = 0x74 */
7254 gint len = QT_UINT32 (stsd_data);
7257 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
7259 _gst_buffer_copy_into_mem (buf, 0, stsd_data + 0x4C, len - 0x4C);
7260 gst_caps_set_simple (stream->caps,
7261 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7262 gst_buffer_unref (buf);
7264 gst_caps_set_simple (stream->caps,
7265 "samplesize", G_TYPE_INT, samplesize, NULL);
7270 GNode *alac, *wave = NULL;
7272 /* apparently, m4a has this atom appended directly in the stsd entry,
7273 * while mov has it in a wave atom */
7274 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
7276 /* alac now refers to stsd entry atom */
7277 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
7279 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
7281 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
7284 gint len = QT_UINT32 (alac->data);
7288 GST_DEBUG_OBJECT (qtdemux,
7289 "discarding alac atom with unexpected len %d", len);
7291 /* codec-data contains alac atom size and prefix,
7292 * ffmpeg likes it that way, not quite gst-ish though ...*/
7293 buf = gst_buffer_new_and_alloc (len);
7294 _gst_buffer_copy_into_mem (buf, 0, alac->data, len);
7295 gst_caps_set_simple (stream->caps,
7296 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7297 gst_buffer_unref (buf);
7300 gst_caps_set_simple (stream->caps,
7301 "samplesize", G_TYPE_INT, samplesize, NULL);
7309 gint len = QT_UINT32 (stsd_data);
7312 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
7315 _gst_buffer_copy_into_mem (buf, 0, stsd_data + 0x34, len - 0x34);
7317 /* If we have enough data, let's try to get the 'damr' atom. See
7318 * the 3GPP container spec (26.244) for more details. */
7319 if ((len - 0x34) > 8 &&
7320 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
7322 list = gst_tag_list_new_empty ();
7323 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7324 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
7327 gst_caps_set_simple (stream->caps,
7328 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7329 gst_buffer_unref (buf);
7337 GST_INFO_OBJECT (qtdemux,
7338 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
7339 GST_FOURCC_ARGS (fourcc), stream->caps);
7341 } else if (stream->subtype == FOURCC_strm) {
7342 if (fourcc == FOURCC_rtsp) {
7343 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
7345 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
7346 GST_FOURCC_ARGS (fourcc));
7347 goto unknown_stream;
7349 stream->sampled = TRUE;
7350 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text) {
7352 stream->sampled = TRUE;
7357 qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
7359 list = gst_tag_list_new_empty ();
7360 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7361 GST_TAG_SUBTITLE_CODEC, codec, NULL);
7366 /* hunt for sort-of codec data */
7373 /* look for palette */
7374 /* target mp4s atom */
7375 len = QT_UINT32 (stsd_data + offset);
7376 data = stsd_data + offset;
7377 /* verify sufficient length,
7378 * and esds present with decConfigDescr of expected size and position */
7379 if ((len >= 106 + 8)
7380 && (QT_FOURCC (data + 8 + 8 + 4) == FOURCC_esds)
7381 && (QT_UINT16 (data + 8 + 40) == 0x0540)) {
7386 /* move to decConfigDescr data */
7387 data = data + 8 + 42;
7388 for (i = 0; i < 16; i++) {
7389 clut[i] = QT_UINT32 (data);
7393 s = gst_structure_new ("application/x-gst-dvd", "event",
7394 G_TYPE_STRING, "dvd-spu-clut-change",
7395 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
7396 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
7397 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
7398 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
7399 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
7400 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
7401 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
7402 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
7405 /* store event and trigger custom processing */
7406 stream->pending_event =
7407 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
7408 stream->need_process = TRUE;
7416 goto unknown_stream;
7419 /* promote to sampled format */
7420 if (stream->fourcc == FOURCC_samr) {
7421 /* force mono 8000 Hz for AMR */
7422 stream->sampled = TRUE;
7423 stream->n_channels = 1;
7424 stream->rate = 8000;
7425 } else if (stream->fourcc == FOURCC_sawb) {
7426 /* force mono 16000 Hz for AMR-WB */
7427 stream->sampled = TRUE;
7428 stream->n_channels = 1;
7429 stream->rate = 16000;
7430 } else if (stream->fourcc == FOURCC_mp4a) {
7431 stream->sampled = TRUE;
7434 /* collect sample information */
7435 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
7436 goto samples_failed;
7438 if (qtdemux->fragmented) {
7442 /* need all moov samples as basis; probably not many if any at all */
7443 /* prevent moof parsing taking of at this time */
7444 offset = qtdemux->moof_offset;
7445 qtdemux->moof_offset = 0;
7446 if (stream->n_samples &&
7447 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
7448 qtdemux->moof_offset = offset;
7449 goto samples_failed;
7451 qtdemux->moof_offset = 0;
7452 /* movie duration more reliable in this case (e.g. mehd) */
7453 if (qtdemux->segment.duration &&
7454 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
7455 stream->duration = gst_util_uint64_scale (qtdemux->segment.duration,
7456 stream->timescale, GST_SECOND);
7457 /* need defaults for fragments */
7458 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
7461 /* configure segments */
7462 if (!qtdemux_parse_segments (qtdemux, stream, trak))
7463 goto segments_failed;
7465 /* add some language tag, if useful */
7466 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
7467 strcmp (stream->lang_id, "und")) {
7468 const gchar *lang_code;
7471 list = gst_tag_list_new_empty ();
7473 /* convert ISO 639-2 code to ISO 639-1 */
7474 lang_code = gst_tag_get_language_code (stream->lang_id);
7475 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7476 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
7479 /* now we are ready to add the stream */
7480 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
7481 goto too_many_streams;
7483 stream->pending_tags = list;
7484 qtdemux->streams[qtdemux->n_streams] = stream;
7485 qtdemux->n_streams++;
7486 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
7493 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7494 (_("This file is corrupt and cannot be played.")), (NULL));
7500 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
7507 /* we posted an error already */
7508 /* free stbl sub-atoms */
7509 gst_qtdemux_stbl_free (stream);
7515 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
7516 GST_FOURCC_ARGS (stream->subtype));
7522 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
7523 (_("This file contains too many streams. Only playing first %d"),
7524 GST_QTDEMUX_MAX_STREAMS), (NULL));
7529 /* If we can estimate the overall bitrate, and don't have information about the
7530 * stream bitrate for exactly one stream, this guesses the stream bitrate as
7531 * the overall bitrate minus the sum of the bitrates of all other streams. This
7532 * should be useful for the common case where we have one audio and one video
7533 * stream and can estimate the bitrate of one, but not the other. */
7535 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
7537 QtDemuxStream *stream = NULL;
7538 gint64 size, duration, sys_bitrate, sum_bitrate = 0;
7542 if (qtdemux->fragmented)
7545 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
7547 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)) {
7548 GST_DEBUG_OBJECT (qtdemux,
7549 "Size in bytes of the stream not known - bailing");
7553 /* Subtract the header size */
7554 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
7555 size, qtdemux->header_size);
7556 g_assert (size >= qtdemux->header_size);
7557 size = size - qtdemux->header_size;
7559 if (!gst_qtdemux_get_duration (qtdemux, &duration) ||
7560 duration == GST_CLOCK_TIME_NONE) {
7561 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
7565 for (i = 0; i < qtdemux->n_streams; i++) {
7566 switch (qtdemux->streams[i]->subtype) {
7569 /* retrieve bitrate, prefer avg then max */
7571 if (qtdemux->streams[i]->pending_tags) {
7572 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
7573 GST_TAG_MAXIMUM_BITRATE, &bitrate);
7574 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
7575 GST_TAG_BITRATE, &bitrate);
7578 sum_bitrate += bitrate;
7581 GST_DEBUG_OBJECT (qtdemux,
7582 ">1 stream with unknown bitrate - bailing");
7585 stream = qtdemux->streams[i];
7589 /* For other subtypes, we assume no significant impact on bitrate */
7595 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
7599 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
7601 if (sys_bitrate < sum_bitrate) {
7602 /* This can happen, since sum_bitrate might be derived from maximum
7603 * bitrates and not average bitrates */
7604 GST_DEBUG_OBJECT (qtdemux,
7605 "System bitrate less than sum bitrate - bailing");
7609 bitrate = sys_bitrate - sum_bitrate;
7610 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
7611 ", Stream bitrate = %u", sys_bitrate, bitrate);
7613 if (!stream->pending_tags)
7614 stream->pending_tags = gst_tag_list_new_empty ();
7616 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
7617 GST_TAG_BITRATE, bitrate, NULL);
7620 static GstFlowReturn
7621 qtdemux_expose_streams (GstQTDemux * qtdemux)
7624 GstFlowReturn ret = GST_FLOW_OK;
7626 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
7628 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
7629 QtDemuxStream *stream = qtdemux->streams[i];
7630 guint32 sample_num = 0;
7635 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
7636 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
7638 if (qtdemux->fragmented) {
7639 /* need all moov samples first */
7640 GST_OBJECT_LOCK (qtdemux);
7641 while (stream->n_samples == 0)
7642 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
7644 GST_OBJECT_UNLOCK (qtdemux);
7646 /* discard any stray moof */
7647 qtdemux->moof_offset = 0;
7650 /* prepare braking */
7651 if (ret != GST_FLOW_ERROR)
7654 /* in pull mode, we should have parsed some sample info by now;
7655 * and quite some code will not handle no samples.
7656 * in push mode, we'll just have to deal with it */
7657 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
7658 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
7659 gst_qtdemux_stream_free (qtdemux, stream);
7660 memmove (&(qtdemux->streams[i]), &(qtdemux->streams[i + 1]),
7661 sizeof (QtDemuxStream *) * (GST_QTDEMUX_MAX_STREAMS - i - 1));
7662 qtdemux->streams[GST_QTDEMUX_MAX_STREAMS - 1] = NULL;
7663 qtdemux->n_streams--;
7668 /* parse number of initial sample to set frame rate cap */
7669 while (sample_num < stream->n_samples && sample_num < samples) {
7670 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
7674 /* collect and sort durations */
7675 samples = MIN (stream->stbl_index + 1, samples);
7676 GST_DEBUG_OBJECT (qtdemux, "%d samples for framerate", samples);
7678 durations = g_array_sized_new (FALSE, FALSE, sizeof (guint32), samples);
7680 while (sample_num < samples) {
7681 g_array_append_val (durations, stream->samples[sample_num].duration);
7684 g_array_sort (durations, less_than);
7685 stream->min_duration = g_array_index (durations, guint32, samples / 2);
7686 g_array_free (durations, TRUE);
7689 /* now we have all info and can expose */
7690 list = stream->pending_tags;
7691 stream->pending_tags = NULL;
7692 gst_qtdemux_add_stream (qtdemux, stream, list);
7695 gst_qtdemux_guess_bitrate (qtdemux);
7697 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
7699 /* check if we should post a redirect in case there is a single trak
7700 * and it is a redirecting trak */
7701 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
7704 qtdemux_post_global_tags (qtdemux);
7706 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
7707 "an external content");
7708 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
7709 gst_structure_new ("redirect",
7710 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
7712 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
7713 qtdemux->posted_redirect = TRUE;
7719 /* check if major or compatible brand is 3GP */
7720 static inline gboolean
7721 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
7724 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
7725 GST_MAKE_FOURCC ('3', 'g', 0, 0));
7726 } else if (qtdemux->comp_brands != NULL) {
7730 gboolean res = FALSE;
7732 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
7736 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
7737 GST_MAKE_FOURCC ('3', 'g', 0, 0));
7741 gst_buffer_unmap (qtdemux->comp_brands, &map);
7748 /* check if tag is a spec'ed 3GP tag keyword storing a string */
7749 static inline gboolean
7750 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
7752 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
7753 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
7754 || fourcc == FOURCC_albm;
7758 qtdemux_tag_add_location (GstQTDemux * qtdemux, const char *tag,
7759 const char *dummy, GNode * node)
7761 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
7765 gdouble longitude, latitude, altitude;
7768 len = QT_UINT32 (node->data);
7775 /* TODO: language code skipped */
7777 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
7780 /* do not alarm in trivial case, but bail out otherwise */
7781 if (*(data + offset) != 0) {
7782 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
7786 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
7787 GST_TAG_GEO_LOCATION_NAME, name, NULL);
7788 offset += strlen (name);
7792 if (len < offset + 2 + 4 + 4 + 4)
7795 /* +1 +1 = skip null-terminator and location role byte */
7797 /* table in spec says unsigned, semantics say negative has meaning ... */
7798 longitude = QT_SFP32 (data + offset);
7801 latitude = QT_SFP32 (data + offset);
7804 altitude = QT_SFP32 (data + offset);
7806 /* one invalid means all are invalid */
7807 if (longitude >= -180.0 && longitude <= 180.0 &&
7808 latitude >= -90.0 && latitude <= 90.0) {
7809 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
7810 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
7811 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
7812 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
7815 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
7822 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
7829 qtdemux_tag_add_year (GstQTDemux * qtdemux, const char *tag, const char *dummy,
7836 len = QT_UINT32 (node->data);
7840 y = QT_UINT16 ((guint8 *) node->data + 12);
7842 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
7845 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
7847 date = g_date_new_dmy (1, 1, y);
7848 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, date, NULL);
7853 qtdemux_tag_add_classification (GstQTDemux * qtdemux, const char *tag,
7854 const char *dummy, GNode * node)
7857 char *tag_str = NULL;
7862 len = QT_UINT32 (node->data);
7867 entity = (guint8 *) node->data + offset;
7868 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
7869 GST_DEBUG_OBJECT (qtdemux,
7870 "classification info: %c%c%c%c invalid classification entity",
7871 entity[0], entity[1], entity[2], entity[3]);
7876 table = QT_UINT16 ((guint8 *) node->data + offset);
7878 /* Language code skipped */
7882 /* Tag format: "XXXX://Y[YYYY]/classification info string"
7883 * XXXX: classification entity, fixed length 4 chars.
7884 * Y[YYYY]: classification table, max 5 chars.
7886 tag_str = g_strdup_printf ("----://%u/%s",
7887 table, (char *) node->data + offset);
7889 /* memcpy To be sure we're preserving byte order */
7890 memcpy (tag_str, entity, 4);
7891 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
7893 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_APPEND, tag,
7903 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
7909 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, const char *tag,
7910 const char *dummy, GNode * node)
7912 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
7918 gboolean ret = TRUE;
7920 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
7922 len = QT_UINT32 (data->data);
7923 type = QT_UINT32 ((guint8 *) data->data + 8);
7924 if (type == 0x00000001 && len > 16) {
7925 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
7928 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
7929 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s,
7933 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
7937 len = QT_UINT32 (node->data);
7938 type = QT_UINT32 ((guint8 *) node->data + 4);
7939 if ((type >> 24) == 0xa9) {
7940 /* Type starts with the (C) symbol, so the next 32 bits are
7941 * the language code, which we ignore */
7943 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
7944 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
7945 QT_FOURCC ((guint8 *) node->data + 4))) {
7946 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
7948 /* we go for 3GP style encoding if major brands claims so,
7949 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
7950 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
7951 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
7952 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
7954 /* 16-bit Language code is ignored here as well */
7955 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
7962 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
7963 ret = FALSE; /* may have to fallback */
7965 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
7966 len - offset, env_vars);
7968 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
7969 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s, NULL);
7973 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
7980 qtdemux_tag_add_str (GstQTDemux * qtdemux, const char *tag,
7981 const char *dummy, GNode * node)
7983 qtdemux_tag_add_str_full (qtdemux, tag, dummy, node);
7987 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, const char *tag,
7988 const char *dummy, GNode * node)
7990 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
7992 char *s, *t, *k = NULL;
7997 /* first try normal string tag if major brand not 3GP */
7998 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
7999 if (!qtdemux_tag_add_str_full (qtdemux, tag, dummy, node)) {
8000 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
8001 * let's try it 3gpp way after minor safety check */
8003 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
8009 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
8013 len = QT_UINT32 (data);
8017 count = QT_UINT8 (data + 14);
8019 for (; count; count--) {
8022 if (offset + 1 > len)
8024 slen = QT_UINT8 (data + offset);
8026 if (offset + slen > len)
8028 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
8031 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
8033 t = g_strjoin (",", k, s, NULL);
8041 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
8048 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
8049 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, k, NULL);
8058 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
8064 qtdemux_tag_add_num (GstQTDemux * qtdemux, const char *tag1,
8065 const char *tag2, GNode * node)
8072 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8074 len = QT_UINT32 (data->data);
8075 type = QT_UINT32 ((guint8 *) data->data + 8);
8076 if (type == 0x00000000 && len >= 22) {
8077 n1 = QT_UINT16 ((guint8 *) data->data + 18);
8078 n2 = QT_UINT16 ((guint8 *) data->data + 20);
8080 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
8081 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8085 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
8086 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8094 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
8102 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8104 len = QT_UINT32 (data->data);
8105 type = QT_UINT32 ((guint8 *) data->data + 8);
8106 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
8107 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
8108 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
8109 n1 = QT_UINT16 ((guint8 *) data->data + 16);
8111 /* do not add bpm=0 */
8112 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
8113 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8114 tag1, (gdouble) n1, NULL);
8121 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, const char *tag1,
8122 const char *dummy, GNode * node)
8129 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8131 len = QT_UINT32 (data->data);
8132 type = QT_UINT32 ((guint8 *) data->data + 8);
8133 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
8134 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
8135 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
8136 num = QT_UINT32 ((guint8 *) data->data + 16);
8138 /* do not add num=0 */
8139 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
8140 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8148 qtdemux_tag_add_covr (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
8156 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8158 len = QT_UINT32 (data->data);
8159 type = QT_UINT32 ((guint8 *) data->data + 8);
8160 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
8161 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
8163 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
8164 len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
8165 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
8166 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8167 tag1, sample, NULL);
8168 gst_sample_unref (sample);
8175 qtdemux_tag_add_date (GstQTDemux * qtdemux, const char *tag, const char *dummy,
8183 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8185 len = QT_UINT32 (data->data);
8186 type = QT_UINT32 ((guint8 *) data->data + 8);
8187 if (type == 0x00000001 && len > 16) {
8188 guint y, m = 1, d = 1;
8191 s = g_strndup ((char *) data->data + 16, len - 16);
8192 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
8193 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
8194 if (ret >= 1 && y > 1500 && y < 3000) {
8197 date = g_date_new_dmy (d, m, y);
8198 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag,
8202 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
8210 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, const char *tag, const char *dummy,
8215 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8217 /* re-route to normal string tag if major brand says so
8218 * or no data atom and compatible brand suggests so */
8219 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
8220 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
8221 qtdemux_tag_add_str (qtdemux, tag, dummy, node);
8228 len = QT_UINT32 (data->data);
8229 type = QT_UINT32 ((guint8 *) data->data + 8);
8230 if (type == 0x00000000 && len >= 18) {
8231 n = QT_UINT16 ((guint8 *) data->data + 16);
8235 genre = gst_tag_id3_genre_get (n - 1);
8236 if (genre != NULL) {
8237 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
8238 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8247 qtdemux_add_double_tag_from_str (GstQTDemux * demux, const gchar * tag,
8248 guint8 * data, guint32 datasize)
8253 /* make a copy to have \0 at the end */
8254 datacopy = g_strndup ((gchar *) data, datasize);
8256 /* convert the str to double */
8257 if (sscanf (datacopy, "%lf", &value) == 1) {
8258 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
8259 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_REPLACE, tag, value, NULL);
8261 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
8269 qtdemux_tag_add_revdns (GstQTDemux * demux, const char *tag,
8270 const char *tag_bis, GNode * node)
8279 const gchar *meanstr;
8280 const gchar *namestr;
8282 /* checking the whole ---- atom size for consistency */
8283 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
8284 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
8288 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
8290 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
8294 meansize = QT_UINT32 (mean->data);
8295 if (meansize <= 12) {
8296 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
8299 meanstr = ((gchar *) mean->data) + 12;
8301 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
8303 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
8307 namesize = QT_UINT32 (name->data);
8308 if (namesize <= 12) {
8309 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
8312 namestr = ((gchar *) name->data) + 12;
8319 * uint24 - data type
8323 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
8325 GST_WARNING_OBJECT (demux, "No data atom in this tag");
8328 datasize = QT_UINT32 (data->data);
8329 if (datasize <= 16) {
8330 GST_WARNING_OBJECT (demux, "Data atom too small");
8333 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
8335 if (strncmp (meanstr, "com.apple.iTunes", meansize - 12) == 0) {
8338 const gchar name[28];
8339 const gchar tag[28];
8342 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
8343 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
8344 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
8345 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
8346 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
8347 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
8348 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
8349 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
8353 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
8354 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize - 12)) {
8355 switch (gst_tag_get_type (tags[i].tag)) {
8357 qtdemux_add_double_tag_from_str (demux, tags[i].tag,
8358 ((guint8 *) data->data) + 16, datasize - 16);
8361 qtdemux_tag_add_str (demux, tags[i].tag, NULL, node);
8370 if (i == G_N_ELEMENTS (tags))
8384 meanstr_dbg = g_strndup (meanstr, meansize - 12);
8385 namestr_dbg = g_strndup (namestr, namesize - 12);
8387 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
8388 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
8390 g_free (namestr_dbg);
8391 g_free (meanstr_dbg);
8397 qtdemux_tag_add_id32 (GstQTDemux * demux, const char *tag,
8398 const char *tag_bis, GNode * node)
8403 GstTagList *taglist = NULL;
8405 GST_LOG_OBJECT (demux, "parsing ID32");
8408 len = GST_READ_UINT32_BE (data);
8410 /* need at least full box and language tag */
8414 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
8415 gst_buffer_fill (buf, 0, data + 14, len - 14);
8417 taglist = gst_tag_list_from_id3v2_tag (buf);
8419 GST_LOG_OBJECT (demux, "parsing ok");
8420 gst_tag_list_insert (demux->tag_list, taglist, GST_TAG_MERGE_KEEP);
8422 GST_LOG_OBJECT (demux, "parsing failed");
8426 gst_tag_list_free (taglist);
8428 gst_buffer_unref (buf);
8431 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux,
8432 const char *tag, const char *tag_bis, GNode * node);
8435 FOURCC_pcst -> if media is a podcast -> bool
8436 FOURCC_cpil -> if media is part of a compilation -> bool
8437 FOURCC_pgap -> if media is part of a gapless context -> bool
8438 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
8444 const gchar *gst_tag;
8445 const gchar *gst_tag_bis;
8446 const GstQTDemuxAddTagFunc func;
8449 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
8450 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
8451 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
8452 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
8453 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
8454 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
8455 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
8456 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
8457 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
8458 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
8459 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
8460 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
8461 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
8462 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
8463 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
8464 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
8465 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
8466 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
8467 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
8468 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
8469 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
8470 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
8471 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
8472 qtdemux_tag_add_num}, {
8473 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
8474 qtdemux_tag_add_num}, {
8475 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
8476 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
8477 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
8478 FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
8479 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
8480 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
8481 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
8482 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
8483 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
8484 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
8485 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
8486 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
8487 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
8488 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
8489 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
8490 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
8491 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
8492 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
8493 qtdemux_tag_add_classification}, {
8495 /* This is a special case, some tags are stored in this
8496 * 'reverse dns naming', according to:
8497 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
8500 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
8501 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
8502 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
8506 qtdemux_tag_add_blob (GNode * node, GstQTDemux * demux)
8518 len = QT_UINT32 (data);
8519 buf = gst_buffer_new_and_alloc (len);
8520 _gst_buffer_copy_into_mem (buf, 0, data, len);
8522 /* heuristic to determine style of tag */
8523 if (QT_FOURCC (data + 4) == FOURCC_____ ||
8524 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
8526 else if (demux->major_brand == FOURCC_qt__)
8527 style = "quicktime";
8528 /* fall back to assuming iso/3gp tag style */
8532 /* santize the name for the caps. */
8533 for (i = 0; i < 4; i++) {
8534 guint8 d = data[4 + i];
8535 if (g_ascii_isalnum (d))
8536 ndata[i] = g_ascii_tolower (d);
8541 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
8542 ndata[0], ndata[1], ndata[2], ndata[3]);
8543 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
8545 caps = gst_caps_new_simple (media_type, "style", G_TYPE_STRING, style, NULL);
8546 // TODO conver to metadata or ???
8547 // gst_buffer_set_caps (buf, caps);
8548 gst_caps_unref (caps);
8549 g_free (media_type);
8551 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, caps %" GST_PTR_FORMAT,
8554 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_APPEND,
8555 GST_QT_DEMUX_PRIVATE_TAG, buf, NULL);
8556 gst_buffer_unref (buf);
8560 qtdemux_parse_udta (GstQTDemux * qtdemux, GNode * udta)
8568 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
8570 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
8572 GST_LOG_OBJECT (qtdemux, "no ilst");
8577 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
8580 GST_DEBUG_OBJECT (qtdemux, "new tag list");
8581 if (!qtdemux->tag_list)
8582 qtdemux->tag_list = gst_tag_list_new_empty ();
8585 while (i < G_N_ELEMENTS (add_funcs)) {
8586 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
8590 len = QT_UINT32 (node->data);
8592 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
8593 GST_FOURCC_ARGS (add_funcs[i].fourcc));
8595 add_funcs[i].func (qtdemux, add_funcs[i].gst_tag,
8596 add_funcs[i].gst_tag_bis, node);
8598 g_node_destroy (node);
8604 /* parsed nodes have been removed, pass along remainder as blob */
8605 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
8606 (GNodeForeachFunc) qtdemux_tag_add_blob, qtdemux);
8608 /* parse up XMP_ node if existing */
8609 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
8612 GstTagList *taglist;
8614 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
8615 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
8616 taglist = gst_tag_list_from_xmp_buffer (buf);
8617 gst_buffer_unref (buf);
8619 qtdemux_handle_xmp_taglist (qtdemux, taglist);
8621 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
8628 GstStructure *structure; /* helper for sort function */
8630 guint min_req_bitrate;
8631 guint min_req_qt_version;
8635 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
8637 GstQtReference *ref_a = (GstQtReference *) a;
8638 GstQtReference *ref_b = (GstQtReference *) b;
8640 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
8641 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
8643 /* known bitrates go before unknown; higher bitrates go first */
8644 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
8647 /* sort the redirects and post a message for the application.
8650 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
8652 GstQtReference *best;
8655 GValue list_val = { 0, };
8658 g_assert (references != NULL);
8660 references = g_list_sort (references, qtdemux_redirects_sort_func);
8662 best = (GstQtReference *) references->data;
8664 g_value_init (&list_val, GST_TYPE_LIST);
8666 for (l = references; l != NULL; l = l->next) {
8667 GstQtReference *ref = (GstQtReference *) l->data;
8668 GValue struct_val = { 0, };
8670 ref->structure = gst_structure_new ("redirect",
8671 "new-location", G_TYPE_STRING, ref->location, NULL);
8673 if (ref->min_req_bitrate > 0) {
8674 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
8675 ref->min_req_bitrate, NULL);
8678 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
8679 g_value_set_boxed (&struct_val, ref->structure);
8680 gst_value_list_append_value (&list_val, &struct_val);
8681 g_value_unset (&struct_val);
8682 /* don't free anything here yet, since we need best->structure below */
8685 g_assert (best != NULL);
8686 s = gst_structure_copy (best->structure);
8688 if (g_list_length (references) > 1) {
8689 gst_structure_set_value (s, "locations", &list_val);
8692 g_value_unset (&list_val);
8694 for (l = references; l != NULL; l = l->next) {
8695 GstQtReference *ref = (GstQtReference *) l->data;
8697 gst_structure_free (ref->structure);
8698 g_free (ref->location);
8701 g_list_free (references);
8703 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
8704 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
8705 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
8706 qtdemux->posted_redirect = TRUE;
8709 /* look for redirect nodes, collect all redirect information and
8713 qtdemux_parse_redirects (GstQTDemux * qtdemux)
8715 GNode *rmra, *rmda, *rdrf;
8717 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
8719 GList *redirects = NULL;
8721 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
8723 GstQtReference ref = { NULL, NULL, 0, 0 };
8726 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
8727 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
8728 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
8729 ref.min_req_bitrate);
8732 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
8733 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
8734 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
8736 #ifndef GST_DISABLE_GST_DEBUG
8737 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
8739 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
8741 GST_LOG_OBJECT (qtdemux,
8742 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
8743 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
8744 bitmask, check_type);
8745 if (package == FOURCC_qtim && check_type == 0) {
8746 ref.min_req_qt_version = version;
8750 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
8755 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
8756 ref_data = (guint8 *) rdrf->data + 20;
8757 if (ref_type == FOURCC_alis) {
8758 guint record_len, record_version, fn_len;
8760 /* MacOSX alias record, google for alias-layout.txt */
8761 record_len = QT_UINT16 (ref_data + 4);
8762 record_version = QT_UINT16 (ref_data + 4 + 2);
8763 fn_len = QT_UINT8 (ref_data + 50);
8764 if (record_len > 50 && record_version == 2 && fn_len > 0) {
8765 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
8767 } else if (ref_type == FOURCC_url_) {
8768 ref.location = g_strdup ((gchar *) ref_data);
8770 GST_DEBUG_OBJECT (qtdemux,
8771 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
8772 GST_FOURCC_ARGS (ref_type));
8774 if (ref.location != NULL) {
8775 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
8776 redirects = g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
8778 GST_WARNING_OBJECT (qtdemux,
8779 "Failed to extract redirect location from rdrf atom");
8783 /* look for others */
8784 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
8787 if (redirects != NULL) {
8788 qtdemux_process_redirects (qtdemux, redirects);
8795 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
8800 tags = gst_tag_list_new_empty ();
8802 if (qtdemux->major_brand == FOURCC_mjp2)
8803 fmt = "Motion JPEG 2000";
8804 else if ((qtdemux->major_brand & 0xffff) == GST_MAKE_FOURCC ('3', 'g', 0, 0))
8806 else if (qtdemux->major_brand == FOURCC_qt__)
8808 else if (qtdemux->fragmented)
8811 fmt = "ISO MP4/M4A";
8813 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
8814 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
8816 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
8822 /* we have read th complete moov node now.
8823 * This function parses all of the relevant info, creates the traks and
8824 * prepares all data structures for playback
8827 qtdemux_parse_tree (GstQTDemux * qtdemux)
8834 guint64 creation_time;
8835 GstDateTime *datetime = NULL;
8838 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
8840 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
8841 return qtdemux_parse_redirects (qtdemux);
8844 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
8846 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
8847 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
8848 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
8849 } else if (version == 0) {
8850 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
8851 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
8852 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
8854 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
8858 /* Moving qt creation time (secs since 1904) to unix time */
8859 if (creation_time != 0) {
8860 if (creation_time > QTDEMUX_SECONDS_FROM_1904_TO_1970) {
8863 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
8864 /* some data cleansing sanity */
8865 g_get_current_time (&now);
8866 if (now.tv_sec + 24 * 3600 < creation_time) {
8867 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
8869 datetime = gst_date_time_new_from_unix_epoch_local_time (creation_time);
8872 GST_WARNING_OBJECT (qtdemux, "Can't handle datetimes before 1970 yet, "
8873 "please file a bug at http://bugzilla.gnome.org");
8877 if (!qtdemux->tag_list)
8878 qtdemux->tag_list = gst_tag_list_new_empty ();
8880 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
8881 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
8883 gst_date_time_unref (datetime);
8886 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
8887 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
8889 /* check for fragmented file and get some (default) data */
8890 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
8893 GstByteReader mehd_data;
8895 /* let track parsing or anyone know weird stuff might happen ... */
8896 qtdemux->fragmented = TRUE;
8898 /* compensate for total duration */
8899 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
8901 qtdemux_parse_mehd (qtdemux, &mehd_data);
8904 /* set duration in the segment info */
8905 gst_qtdemux_get_duration (qtdemux, &duration);
8907 qtdemux->segment.duration = duration;
8908 /* also do not exceed duration; stop is set that way post seek anyway,
8909 * and segment activation falls back to duration,
8910 * whereas loop only checks stop, so let's align this here as well */
8911 qtdemux->segment.stop = duration;
8914 /* parse all traks */
8915 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
8917 qtdemux_parse_trak (qtdemux, trak);
8918 /* iterate all siblings */
8919 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
8923 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
8925 qtdemux_parse_udta (qtdemux, udta);
8927 GST_LOG_OBJECT (qtdemux, "No udta node found.");
8930 /* maybe also some tags in meta box */
8931 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
8933 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
8934 qtdemux_parse_udta (qtdemux, udta);
8936 GST_LOG_OBJECT (qtdemux, "No meta node found.");
8939 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
8944 /* taken from ffmpeg */
8946 get_size (guint8 * ptr, guint8 ** end)
8955 len = (len << 7) | (c & 0x7f);
8964 /* this can change the codec originally present in @list */
8966 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
8967 GNode * esds, GstTagList * list)
8969 int len = QT_UINT32 (esds->data);
8970 guint8 *ptr = esds->data;
8971 guint8 *end = ptr + len;
8973 guint8 *data_ptr = NULL;
8975 guint8 object_type_id = 0;
8976 const char *codec_name = NULL;
8977 GstCaps *caps = NULL;
8979 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
8981 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
8984 tag = QT_UINT8 (ptr);
8985 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
8987 len = get_size (ptr, &ptr);
8988 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
8992 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
8993 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
8997 guint max_bitrate, avg_bitrate;
8999 object_type_id = QT_UINT8 (ptr);
9000 max_bitrate = QT_UINT32 (ptr + 5);
9001 avg_bitrate = QT_UINT32 (ptr + 9);
9002 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
9003 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
9004 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
9005 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
9006 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
9007 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
9008 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
9009 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
9011 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
9012 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
9019 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
9025 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
9029 GST_ERROR_OBJECT (qtdemux, "parse error");
9034 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
9035 * in use, and should also be used to override some other parameters for some
9037 switch (object_type_id) {
9038 case 0x20: /* MPEG-4 */
9039 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
9040 * profile_and_level_indication */
9041 if (data_ptr != NULL && data_len >= 5 &&
9042 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
9043 gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
9044 data_ptr + 4, data_len - 4);
9046 break; /* Nothing special needed here */
9047 case 0x21: /* H.264 */
9048 codec_name = "H.264 / AVC";
9049 caps = gst_caps_new_simple ("video/x-h264",
9050 "stream-format", G_TYPE_STRING, "avc",
9051 "alignment", G_TYPE_STRING, "au", NULL);
9053 case 0x40: /* AAC (any) */
9054 case 0x66: /* AAC Main */
9055 case 0x67: /* AAC LC */
9056 case 0x68: /* AAC SSR */
9057 /* Override channels and rate based on the codec_data, as it's often
9059 /* Only do so for basic setup without HE-AAC extension */
9060 if (data_ptr && data_len == 2) {
9061 guint channels, rateindex, rate;
9063 /* FIXME: add gst_codec_utils_aac_get_{channels|sample_rate}()? */
9064 channels = (data_ptr[1] & 0x7f) >> 3;
9065 if (channels > 0 && channels < 7) {
9066 stream->n_channels = channels;
9067 } else if (channels == 7) {
9068 stream->n_channels = 8;
9071 rateindex = ((data_ptr[0] & 0x7) << 1) | ((data_ptr[1] & 0x80) >> 7);
9072 rate = gst_codec_utils_aac_get_sample_rate_from_index (rateindex);
9074 stream->rate = rate;
9077 /* Set level and profile if possible */
9078 if (data_ptr != NULL && data_len >= 2) {
9079 gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
9080 data_ptr, data_len);
9083 case 0x60: /* MPEG-2, various profiles */
9089 codec_name = "MPEG-2 video";
9091 gst_caps_unref (stream->caps);
9092 stream->caps = gst_caps_new_simple ("video/mpeg",
9093 "mpegversion", G_TYPE_INT, 2,
9094 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9096 case 0x69: /* MP3 has two different values, accept either */
9098 /* change to mpeg1 layer 3 audio */
9099 gst_caps_set_simple (stream->caps, "layer", G_TYPE_INT, 3,
9100 "mpegversion", G_TYPE_INT, 1, NULL);
9101 codec_name = "MPEG-1 layer 3";
9103 case 0x6A: /* MPEG-1 */
9104 codec_name = "MPEG-1 video";
9106 gst_caps_unref (stream->caps);
9107 stream->caps = gst_caps_new_simple ("video/mpeg",
9108 "mpegversion", G_TYPE_INT, 1,
9109 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9111 case 0x6C: /* MJPEG */
9112 caps = gst_caps_new_empty_simple ("image/jpeg");
9113 codec_name = "Motion-JPEG";
9115 case 0x6D: /* PNG */
9116 caps = gst_caps_new_empty_simple ("image/png");
9117 codec_name = "PNG still images";
9119 case 0x6E: /* JPEG2000 */
9120 codec_name = "JPEG-2000";
9121 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
9123 case 0xA4: /* Dirac */
9124 codec_name = "Dirac";
9125 caps = gst_caps_new_empty_simple ("video/x-dirac");
9127 case 0xA5: /* AC3 */
9128 codec_name = "AC-3 audio";
9129 caps = gst_caps_new_simple ("audio/x-ac3",
9130 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
9132 case 0xE1: /* QCELP */
9133 /* QCELP, the codec_data is a riff tag (little endian) with
9134 * 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). */
9135 caps = gst_caps_new_empty_simple ("audio/qcelp");
9136 codec_name = "QCELP";
9142 /* If we have a replacement caps, then change our caps for this stream */
9144 gst_caps_unref (stream->caps);
9145 stream->caps = caps;
9148 if (codec_name && list)
9149 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
9150 GST_TAG_AUDIO_CODEC, codec_name, NULL);
9152 /* Add the codec_data attribute to caps, if we have it */
9156 buffer = gst_buffer_new_and_alloc (data_len);
9157 _gst_buffer_copy_into_mem (buffer, 0, data_ptr, data_len);
9159 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
9160 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
9162 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
9164 gst_buffer_unref (buffer);
9169 #define _codec(name) \
9172 *codec_name = g_strdup (name); \
9177 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
9178 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
9181 const GstStructure *s;
9185 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
9186 _codec ("PNG still images");
9187 caps = gst_caps_new_empty_simple ("image/png");
9189 case GST_MAKE_FOURCC ('j', 'p', 'e', 'g'):
9190 _codec ("JPEG still images");
9191 caps = gst_caps_new_empty_simple ("image/jpeg");
9193 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
9194 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
9195 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
9196 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
9197 _codec ("Motion-JPEG");
9198 caps = gst_caps_new_empty_simple ("image/jpeg");
9200 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
9201 _codec ("Motion-JPEG format B");
9202 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
9204 case GST_MAKE_FOURCC ('m', 'j', 'p', '2'):
9205 _codec ("JPEG-2000");
9206 /* override to what it should be according to spec, avoid palette_data */
9207 stream->bits_per_sample = 24;
9208 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
9210 case GST_MAKE_FOURCC ('S', 'V', 'Q', '3'):
9211 _codec ("Sorensen video v.3");
9212 caps = gst_caps_new_simple ("video/x-svq",
9213 "svqversion", G_TYPE_INT, 3, NULL);
9215 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
9216 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
9217 _codec ("Sorensen video v.1");
9218 caps = gst_caps_new_simple ("video/x-svq",
9219 "svqversion", G_TYPE_INT, 1, NULL);
9221 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
9225 _codec ("Raw RGB video");
9226 bps = QT_UINT16 (stsd_data + 98);
9227 /* set common stuff */
9228 caps = gst_caps_new_empty_simple ("video/x-raw");
9232 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB15", NULL);
9235 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB16", NULL);
9238 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB", NULL);
9241 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "ARGB", NULL);
9249 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
9250 _codec ("Raw planar YUV 4:2:0");
9251 caps = gst_caps_new_simple ("video/x-raw",
9252 "format", G_TYPE_STRING, "I420", NULL);
9254 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
9255 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
9256 _codec ("Raw packed YUV 4:2:2");
9257 caps = gst_caps_new_simple ("video/x-raw",
9258 "format", G_TYPE_STRING, "YUY2", NULL);
9260 case GST_MAKE_FOURCC ('2', 'v', 'u', 'y'):
9261 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
9262 _codec ("Raw packed YUV 4:2:2");
9263 caps = gst_caps_new_simple ("video/x-raw",
9264 "format", G_TYPE_STRING, "UYVY", NULL);
9266 case GST_MAKE_FOURCC ('v', '2', '1', '0'):
9267 _codec ("Raw packed YUV 10-bit 4:2:2");
9268 caps = gst_caps_new_simple ("video/x-raw",
9269 "format", G_TYPE_STRING, "v210", NULL);
9271 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
9272 _codec ("Raw packed RGB 10-bit 4:4:4");
9273 caps = gst_caps_new_simple ("video/x-raw",
9274 "format", G_TYPE_STRING, "r210", NULL);
9276 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
9277 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
9278 _codec ("MPEG-1 video");
9279 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
9280 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9282 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
9283 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
9284 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
9285 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
9286 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080i60 */
9287 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
9288 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
9289 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
9290 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
9291 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
9292 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
9293 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 */
9294 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
9295 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
9296 _codec ("MPEG-2 video");
9297 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
9298 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9300 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
9301 _codec ("GIF still images");
9302 caps = gst_caps_new_empty_simple ("image/gif");
9304 case GST_MAKE_FOURCC ('h', '2', '6', '3'):
9305 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
9306 case GST_MAKE_FOURCC ('s', '2', '6', '3'):
9307 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
9309 /* ffmpeg uses the height/width props, don't know why */
9310 caps = gst_caps_new_empty_simple ("video/x-h263");
9312 case GST_MAKE_FOURCC ('m', 'p', '4', 'v'):
9313 case GST_MAKE_FOURCC ('M', 'P', '4', 'V'):
9314 _codec ("MPEG-4 video");
9315 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
9316 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9318 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
9319 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
9320 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
9321 caps = gst_caps_new_simple ("video/x-msmpeg",
9322 "msmpegversion", G_TYPE_INT, 43, NULL);
9324 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
9325 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
9326 _codec ("3ivX video");
9327 caps = gst_caps_new_empty_simple ("video/x-3ivx");
9329 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
9331 caps = gst_caps_new_simple ("video/x-divx",
9332 "divxversion", G_TYPE_INT, 3, NULL);
9334 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
9335 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
9337 caps = gst_caps_new_simple ("video/x-divx",
9338 "divxversion", G_TYPE_INT, 4, NULL);
9340 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
9342 caps = gst_caps_new_simple ("video/x-divx",
9343 "divxversion", G_TYPE_INT, 5, NULL);
9345 case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
9346 case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
9347 _codec ("XVID MPEG-4");
9348 caps = gst_caps_new_empty_simple ("video/x-xvid");
9351 case GST_MAKE_FOURCC ('F', 'M', 'P', '4'):
9352 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
9353 caps = gst_caps_new_simple ("video/mpeg",
9354 "mpegversion", G_TYPE_INT, 4, NULL);
9356 *codec_name = g_strdup ("FFmpeg MPEG-4");
9359 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
9361 caps = gst_caps_new_empty_simple ("video/x-cinepak");
9363 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
9364 _codec ("Apple QuickDraw");
9365 caps = gst_caps_new_empty_simple ("video/x-qdrw");
9367 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
9368 _codec ("Apple video");
9369 caps = gst_caps_new_empty_simple ("video/x-apple-video");
9371 case GST_MAKE_FOURCC ('a', 'v', 'c', '1'):
9372 _codec ("H.264 / AVC");
9373 caps = gst_caps_new_simple ("video/x-h264",
9374 "stream-format", G_TYPE_STRING, "avc",
9375 "alignment", G_TYPE_STRING, "au", NULL);
9377 case GST_MAKE_FOURCC ('r', 'l', 'e', ' '):
9378 _codec ("Run-length encoding");
9379 caps = gst_caps_new_simple ("video/x-rle",
9380 "layout", G_TYPE_STRING, "quicktime", NULL);
9382 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
9383 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
9384 _codec ("Indeo Video 3");
9385 caps = gst_caps_new_simple ("video/x-indeo",
9386 "indeoversion", G_TYPE_INT, 3, NULL);
9388 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
9389 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
9390 _codec ("Intel Video 4");
9391 caps = gst_caps_new_simple ("video/x-indeo",
9392 "indeoversion", G_TYPE_INT, 4, NULL);
9394 case GST_MAKE_FOURCC ('d', 'v', 'c', 'p'):
9395 case GST_MAKE_FOURCC ('d', 'v', 'c', ' '):
9396 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
9397 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
9398 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
9399 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
9400 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
9401 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
9402 _codec ("DV Video");
9403 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
9404 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9406 case GST_MAKE_FOURCC ('d', 'v', '5', 'n'): /* DVCPRO50 NTSC */
9407 case GST_MAKE_FOURCC ('d', 'v', '5', 'p'): /* DVCPRO50 PAL */
9408 _codec ("DVCPro50 Video");
9409 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
9410 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9412 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
9413 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
9414 _codec ("DVCProHD Video");
9415 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
9416 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
9418 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
9419 _codec ("Apple Graphics (SMC)");
9420 caps = gst_caps_new_empty_simple ("video/x-smc");
9422 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
9424 caps = gst_caps_new_empty_simple ("video/x-vp3");
9426 case GST_MAKE_FOURCC ('X', 'i', 'T', 'h'):
9428 caps = gst_caps_new_empty_simple ("video/x-theora");
9429 /* theora uses one byte of padding in the data stream because it does not
9430 * allow 0 sized packets while theora does */
9431 stream->padding = 1;
9433 case GST_MAKE_FOURCC ('d', 'r', 'a', 'c'):
9435 caps = gst_caps_new_empty_simple ("video/x-dirac");
9437 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
9438 _codec ("TIFF still images");
9439 caps = gst_caps_new_empty_simple ("image/tiff");
9441 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
9442 _codec ("Apple Intermediate Codec");
9443 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
9445 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
9446 _codec ("AVID DNxHD");
9447 caps = gst_caps_from_string ("video/x-dnxhd");
9449 case GST_MAKE_FOURCC ('V', 'P', '8', '0'):
9451 caps = gst_caps_from_string ("video/x-vp8");
9455 caps = gst_caps_new_simple ("video/x-wmv",
9456 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
9458 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
9463 s = g_strdup_printf ("video/x-gst-fourcc-%" GST_FOURCC_FORMAT,
9464 GST_FOURCC_ARGS (fourcc));
9465 caps = gst_caps_new_empty_simple (s);
9470 /* enable clipping for raw video streams */
9471 s = gst_caps_get_structure (caps, 0);
9472 name = gst_structure_get_name (s);
9473 if (g_str_has_prefix (name, "video/x-raw")) {
9474 stream->need_clip = TRUE;
9480 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
9481 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
9484 const GstStructure *s;
9488 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
9491 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
9492 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
9493 _codec ("Raw 8-bit PCM audio");
9494 caps = gst_caps_new_simple ("audio/x-raw",
9495 "format", G_TYPE_STRING, "U8", NULL);
9497 case GST_MAKE_FOURCC ('t', 'w', 'o', 's'):
9498 endian = G_BIG_ENDIAN;
9500 case GST_MAKE_FOURCC ('s', 'o', 'w', 't'):
9504 GstAudioFormat format;
9507 endian = G_LITTLE_ENDIAN;
9509 depth = stream->bytes_per_packet * 8;
9510 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
9512 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
9516 caps = gst_caps_new_simple ("audio/x-raw",
9517 "format", G_TYPE_STRING, gst_audio_format_to_string (format), NULL);
9520 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
9521 _codec ("Raw 64-bit floating-point audio");
9522 caps = gst_caps_new_simple ("audio/x-raw",
9523 "format", G_TYPE_STRING, "F64BE", NULL);
9525 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
9526 _codec ("Raw 32-bit floating-point audio");
9527 caps = gst_caps_new_simple ("audio/x-raw",
9528 "format", G_TYPE_STRING, "F32BE", NULL);
9531 _codec ("Raw 24-bit PCM audio");
9532 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
9534 caps = gst_caps_new_simple ("audio/x-raw",
9535 "format", G_TYPE_STRING, "S24BE", NULL);
9537 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
9538 _codec ("Raw 32-bit PCM audio");
9539 caps = gst_caps_new_simple ("audio/x-raw",
9540 "format", G_TYPE_STRING, "S32BE", NULL);
9542 case GST_MAKE_FOURCC ('u', 'l', 'a', 'w'):
9543 _codec ("Mu-law audio");
9544 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
9546 case GST_MAKE_FOURCC ('a', 'l', 'a', 'w'):
9547 _codec ("A-law audio");
9548 caps = gst_caps_new_empty_simple ("audio/x-alaw");
9552 _codec ("Microsoft ADPCM");
9553 /* Microsoft ADPCM-ACM code 2 */
9554 caps = gst_caps_new_simple ("audio/x-adpcm",
9555 "layout", G_TYPE_STRING, "microsoft", NULL);
9559 _codec ("DVI/IMA ADPCM");
9560 caps = gst_caps_new_simple ("audio/x-adpcm",
9561 "layout", G_TYPE_STRING, "dvi", NULL);
9565 _codec ("DVI/Intel IMA ADPCM");
9566 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
9567 caps = gst_caps_new_simple ("audio/x-adpcm",
9568 "layout", G_TYPE_STRING, "quicktime", NULL);
9572 /* MPEG layer 3, CBR only (pre QT4.1) */
9573 case GST_MAKE_FOURCC ('.', 'm', 'p', '3'):
9574 _codec ("MPEG-1 layer 3");
9575 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
9576 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
9577 "mpegversion", G_TYPE_INT, 1, NULL);
9580 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
9581 _codec ("EAC-3 audio");
9582 caps = gst_caps_new_simple ("audio/x-eac3",
9583 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
9584 stream->sampled = TRUE;
9586 case GST_MAKE_FOURCC ('a', 'c', '-', '3'):
9587 _codec ("AC-3 audio");
9588 caps = gst_caps_new_simple ("audio/x-ac3",
9589 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
9590 stream->sampled = TRUE;
9592 case GST_MAKE_FOURCC ('M', 'A', 'C', '3'):
9594 caps = gst_caps_new_simple ("audio/x-mace",
9595 "maceversion", G_TYPE_INT, 3, NULL);
9597 case GST_MAKE_FOURCC ('M', 'A', 'C', '6'):
9599 caps = gst_caps_new_simple ("audio/x-mace",
9600 "maceversion", G_TYPE_INT, 6, NULL);
9602 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
9604 caps = gst_caps_new_empty_simple ("application/ogg");
9606 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
9607 _codec ("DV audio");
9608 caps = gst_caps_new_empty_simple ("audio/x-dv");
9610 case GST_MAKE_FOURCC ('m', 'p', '4', 'a'):
9611 _codec ("MPEG-4 AAC audio");
9612 caps = gst_caps_new_simple ("audio/mpeg",
9613 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
9614 "stream-format", G_TYPE_STRING, "raw", NULL);
9616 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
9617 _codec ("QDesign Music");
9618 caps = gst_caps_new_empty_simple ("audio/x-qdm");
9620 case GST_MAKE_FOURCC ('Q', 'D', 'M', '2'):
9621 _codec ("QDesign Music v.2");
9622 /* FIXME: QDesign music version 2 (no constant) */
9624 caps = gst_caps_new_simple ("audio/x-qdm2",
9625 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
9626 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
9627 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
9629 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
9632 case GST_MAKE_FOURCC ('a', 'g', 's', 'm'):
9633 _codec ("GSM audio");
9634 caps = gst_caps_new_empty_simple ("audio/x-gsm");
9636 case GST_MAKE_FOURCC ('s', 'a', 'm', 'r'):
9637 _codec ("AMR audio");
9638 caps = gst_caps_new_empty_simple ("audio/AMR");
9640 case GST_MAKE_FOURCC ('s', 'a', 'w', 'b'):
9641 _codec ("AMR-WB audio");
9642 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
9644 case GST_MAKE_FOURCC ('i', 'm', 'a', '4'):
9645 _codec ("Quicktime IMA ADPCM");
9646 caps = gst_caps_new_simple ("audio/x-adpcm",
9647 "layout", G_TYPE_STRING, "quicktime", NULL);
9649 case GST_MAKE_FOURCC ('a', 'l', 'a', 'c'):
9650 _codec ("Apple lossless audio");
9651 caps = gst_caps_new_empty_simple ("audio/x-alac");
9653 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
9654 _codec ("QualComm PureVoice");
9655 caps = gst_caps_from_string ("audio/qcelp");
9659 caps = gst_caps_new_empty_simple ("audio/x-wma");
9661 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
9667 s = g_strdup_printf ("audio/x-gst-fourcc-%" GST_FOURCC_FORMAT,
9668 GST_FOURCC_ARGS (fourcc));
9669 caps = gst_caps_new_empty_simple (s);
9675 GstCaps *templ_caps =
9676 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
9677 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
9678 gst_caps_unref (caps);
9679 gst_caps_unref (templ_caps);
9680 caps = intersection;
9683 /* enable clipping for raw audio streams */
9684 s = gst_caps_get_structure (caps, 0);
9685 name = gst_structure_get_name (s);
9686 if (g_str_has_prefix (name, "audio/x-raw")) {
9687 stream->need_clip = TRUE;
9693 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
9694 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
9698 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
9701 case GST_MAKE_FOURCC ('m', 'p', '4', 's'):
9702 _codec ("DVD subtitle");
9703 caps = gst_caps_new_empty_simple ("video/x-dvd-subpicture");
9705 case GST_MAKE_FOURCC ('t', 'e', 'x', 't'):
9706 _codec ("Quicktime timed text");
9708 case GST_MAKE_FOURCC ('t', 'x', '3', 'g'):
9709 _codec ("3GPP timed text");
9711 caps = gst_caps_new_empty_simple ("text/plain");
9712 /* actual text piece needs to be extracted */
9713 stream->need_process = TRUE;
9719 s = g_strdup_printf ("text/x-gst-fourcc-%" GST_FOURCC_FORMAT,
9720 GST_FOURCC_ARGS (fourcc));
9721 caps = gst_caps_new_empty_simple (s);