2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) <2003> David A. Schleef <ds@schleef.org>
4 * Copyright (C) <2006> Wim Taymans <wim@fluendo.com>
5 * Copyright (C) <2007> Julien Moutte <julien@fluendo.com>
6 * Copyright (C) <2009> Tim-Philipp Müller <tim centricular net>
7 * Copyright (C) <2009> STEricsson <benjamin.gaignard@stericsson.com>
8 * Copyright (C) <2013> Sreerenj Balachandran <sreerenj.balachandran@intel.com>
9 * Copyright (C) <2013> Intel Coroporation
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
20 * You should have received a copy of the GNU Library General Public
21 * License along with this library; if not, write to the
22 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
23 * Boston, MA 02110-1301, USA.
27 * SECTION:element-qtdemux
29 * Demuxes a .mov file into raw or compressed audio and/or video streams.
31 * This element supports both push and pull-based scheduling, depending on the
32 * capabilities of the upstream elements.
35 * <title>Example launch line</title>
37 * gst-launch-1.0 filesrc location=test.mov ! qtdemux name=demux demux.audio_0 ! decodebin ! audioconvert ! audioresample ! autoaudiosink demux.video_0 ! queue ! decodebin ! videoconvert ! videoscale ! autovideosink
38 * ]| Play (parse and decode) a .mov file and try to output it to
39 * an automatically detected soundcard and videosink. If the MOV file contains
40 * compressed audio or video data, this will only work if you have the
41 * right decoder elements/plugins installed.
49 #include "gst/gst-i18n-plugin.h"
51 #include <glib/gprintf.h>
52 #include <gst/tag/tag.h>
53 #include <gst/audio/audio.h>
54 #include <gst/video/video.h>
56 #include "qtatomparser.h"
57 #include "qtdemux_types.h"
58 #include "qtdemux_dump.h"
60 #include "descriptors.h"
61 #include "qtdemux_lang.h"
63 #include "qtpalette.h"
65 #include "gst/riff/riff-media.h"
66 #include "gst/riff/riff-read.h"
68 #include <gst/pbutils/pbutils.h>
75 #include <gst/math-compat.h>
81 /* max. size considered 'sane' for non-mdat atoms */
82 #define QTDEMUX_MAX_ATOM_SIZE (25*1024*1024)
84 /* if the sample index is larger than this, something is likely wrong */
85 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (50*1024*1024)
87 /* For converting qt creation times to unix epoch times */
88 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
89 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
90 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
91 QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
93 #define STREAM_IS_EOS(s) (s->time_position == -1)
95 GST_DEBUG_CATEGORY (qtdemux_debug);
97 /*typedef struct _QtNode QtNode; */
98 typedef struct _QtDemuxSegment QtDemuxSegment;
99 typedef struct _QtDemuxSample QtDemuxSample;
108 struct _QtDemuxSample
111 gint32 pts_offset; /* Add this value to timestamp to get the pts */
113 guint64 timestamp; /* DTS In mov time */
114 guint32 duration; /* In mov time */
115 gboolean keyframe; /* TRUE when this packet is a keyframe */
118 /* timestamp is the DTS */
119 #define QTSAMPLE_DTS(stream,sample) gst_util_uint64_scale ((sample)->timestamp,\
120 GST_SECOND, (stream)->timescale)
121 /* timestamp + offset is the PTS */
122 #define QTSAMPLE_PTS(stream,sample) gst_util_uint64_scale ((sample)->timestamp + \
123 (sample)->pts_offset, GST_SECOND, (stream)->timescale)
124 /* timestamp + duration - dts is the duration */
125 #define QTSAMPLE_DUR_DTS(stream,sample,dts) (gst_util_uint64_scale ((sample)->timestamp + \
126 (sample)->duration, GST_SECOND, (stream)->timescale) - (dts));
128 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
131 * Quicktime has tracks and segments. A track is a continuous piece of
132 * multimedia content. The track is not always played from start to finish but
133 * instead, pieces of the track are 'cut out' and played in sequence. This is
134 * what the segments do.
136 * Inside the track we have keyframes (K) and delta frames. The track has its
137 * own timing, which starts from 0 and extends to end. The position in the track
138 * is called the media_time.
140 * The segments now describe the pieces that should be played from this track
141 * and are basically tuples of media_time/duration/rate entries. We can have
142 * multiple segments and they are all played after one another. An example:
144 * segment 1: media_time: 1 second, duration: 1 second, rate 1
145 * segment 2: media_time: 3 second, duration: 2 second, rate 2
147 * To correctly play back this track, one must play: 1 second of media starting
148 * from media_time 1 followed by 2 seconds of media starting from media_time 3
151 * Each of the segments will be played at a specific time, the first segment at
152 * time 0, the second one after the duration of the first one, etc.. Note that
153 * the time in resulting playback is not identical to the media_time of the
156 * Visually, assuming the track has 4 second of media_time:
159 * .-----------------------------------------------------------.
160 * track: | K.....K.........K........K.......K.......K...........K... |
161 * '-----------------------------------------------------------'
163 * .------------^ ^ .----------^ ^
164 * / .-------------' / .------------------'
166 * .--------------. .--------------.
167 * | segment 1 | | segment 2 |
168 * '--------------' '--------------'
170 * The challenge here is to cut out the right pieces of the track for each of
171 * the playback segments. This fortunately can easily be done with the SEGMENT
172 * events of GStreamer.
174 * For playback of segment 1, we need to provide the decoder with the keyframe
175 * (a), in the above figure, but we must instruct it only to output the decoded
176 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
177 * position set to the time of the segment: 0.
179 * We then proceed to push data from keyframe (a) to frame (b). The decoder
180 * decodes but clips all before media_time 1.
182 * After finishing a segment, we push out a new SEGMENT event with the clipping
183 * boundaries of the new data.
185 * This is a good usecase for the GStreamer accumulated SEGMENT events.
188 struct _QtDemuxSegment
190 /* global time and duration, all gst time */
194 /* media time of trak, all gst time */
200 #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
202 struct _QtDemuxStream
213 gboolean new_stream; /* signals that a stream_start is required */
214 gboolean on_keyframe; /* if this stream last pushed buffer was a
215 * keyframe. This is important to identify
216 * where to stop pushing buffers after a
217 * segment stop time */
219 /* if the stream has a redirect URI in its headers, we store it here */
226 guint64 duration; /* in timescale */
230 gchar lang_id[4]; /* ISO 639-2T language code */
234 QtDemuxSample *samples;
235 gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */
236 guint32 min_duration; /* duration in timescale of first sample, used for figuring out
237 the framerate, in timescale units */
238 guint32 offset_in_sample;
239 guint32 max_buffer_size;
241 /* if we use chunks or samples */
253 /* Numerator/denominator framerate */
256 guint16 bits_per_sample;
257 guint16 color_table_id;
258 GstMemory *rgb8_palette;
263 guint samples_per_packet;
264 guint samples_per_frame;
265 guint bytes_per_packet;
266 guint bytes_per_sample;
267 guint bytes_per_frame;
271 gboolean use_allocator;
272 GstAllocator *allocator;
273 GstAllocationParams params;
275 /* when a discontinuity is pending */
278 /* list of buffers to push first */
281 /* if we need to clip this buffer. This is only needed for uncompressed
285 /* buffer needs some custom processing, e.g. subtitles */
286 gboolean need_process;
288 /* current position */
289 guint32 segment_index;
290 guint32 sample_index;
291 guint64 time_position; /* in gst time */
293 /* the Gst segment we are processing out, used for clipping */
295 guint32 segment_seqnum; /* segment event seqnum obtained from seek */
297 /* last GstFlowReturn */
298 GstFlowReturn last_ret;
300 /* quicktime segments */
302 QtDemuxSegment *segments;
307 GstTagList *pending_tags;
308 gboolean send_global_tags;
310 GstEvent *pending_event;
320 gboolean chunks_are_samples; /* TRUE means treat chunks as samples */
324 GstByteReader co_chunk;
326 guint32 current_chunk;
328 guint32 samples_per_chunk;
329 guint32 stco_sample_index;
331 guint32 sample_size; /* 0 means variable sizes are stored in stsz */
334 guint32 n_samples_per_chunk;
335 guint32 stsc_chunk_index;
336 guint32 stsc_sample_index;
337 guint64 chunk_offset;
340 guint32 stts_samples;
341 guint32 n_sample_times;
342 guint32 stts_sample_index;
344 guint32 stts_duration;
346 gboolean stss_present;
347 guint32 n_sample_syncs;
350 gboolean stps_present;
351 guint32 n_sample_partial_syncs;
354 gboolean ctts_present;
355 guint32 n_composition_times;
357 guint32 ctts_sample_index;
362 gboolean parsed_trex;
363 guint32 def_sample_duration;
364 guint32 def_sample_size;
365 guint32 def_sample_flags;
372 QTDEMUX_STATE_INITIAL, /* Initial state (haven't got the header yet) */
373 QTDEMUX_STATE_HEADER, /* Parsing the header */
374 QTDEMUX_STATE_MOVIE, /* Parsing/Playing the media data */
375 QTDEMUX_STATE_BUFFER_MDAT /* Buffering the mdat atom */
378 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
379 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
380 guint32 fourcc, GstByteReader * parser);
381 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
382 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
383 guint32 fourcc, GstByteReader * parser);
385 static GstStaticPadTemplate gst_qtdemux_sink_template =
386 GST_STATIC_PAD_TEMPLATE ("sink",
389 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
393 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
394 GST_STATIC_PAD_TEMPLATE ("video_%u",
397 GST_STATIC_CAPS_ANY);
399 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
400 GST_STATIC_PAD_TEMPLATE ("audio_%u",
403 GST_STATIC_CAPS_ANY);
405 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
406 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
409 GST_STATIC_CAPS_ANY);
411 #define gst_qtdemux_parent_class parent_class
412 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
414 static void gst_qtdemux_dispose (GObject * object);
417 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
420 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
421 QtDemuxStream * str, gint64 media_offset);
424 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
425 static GstIndex *gst_qtdemux_get_index (GstElement * element);
427 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
428 GstStateChange transition);
429 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
430 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
431 GstObject * parent, GstPadMode mode, gboolean active);
433 static void gst_qtdemux_loop (GstPad * pad);
434 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
436 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
438 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
439 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
440 QtDemuxStream * stream);
441 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
444 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
445 const guint8 * buffer, guint length);
446 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
447 const guint8 * buffer, guint length);
448 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
450 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
451 QtDemuxStream * stream, GNode * esds, GstTagList * list);
452 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
453 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
454 gchar ** codec_name);
455 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
456 QtDemuxStream * stream, guint32 fourcc, const guint8 * data, int len,
457 gchar ** codec_name);
458 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux,
459 QtDemuxStream * stream, guint32 fourcc, const guint8 * data,
460 gchar ** codec_name);
461 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
462 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
463 gchar ** codec_name);
465 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
466 QtDemuxStream * stream, guint32 n);
467 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
468 static void gst_qtdemux_stream_free (GstQTDemux * qtdemux,
469 QtDemuxStream * stream);
470 static void gst_qtdemux_stream_clear (QtDemuxStream * stream);
471 static void gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int index);
472 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
473 static void qtdemux_do_allocation (GstQTDemux * qtdemux,
474 QtDemuxStream * stream);
477 gst_qtdemux_class_init (GstQTDemuxClass * klass)
479 GObjectClass *gobject_class;
480 GstElementClass *gstelement_class;
482 gobject_class = (GObjectClass *) klass;
483 gstelement_class = (GstElementClass *) klass;
485 parent_class = g_type_class_peek_parent (klass);
487 gobject_class->dispose = gst_qtdemux_dispose;
489 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
491 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
492 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
495 gst_tag_register_musicbrainz_tags ();
497 gst_element_class_add_pad_template (gstelement_class,
498 gst_static_pad_template_get (&gst_qtdemux_sink_template));
499 gst_element_class_add_pad_template (gstelement_class,
500 gst_static_pad_template_get (&gst_qtdemux_videosrc_template));
501 gst_element_class_add_pad_template (gstelement_class,
502 gst_static_pad_template_get (&gst_qtdemux_audiosrc_template));
503 gst_element_class_add_pad_template (gstelement_class,
504 gst_static_pad_template_get (&gst_qtdemux_subsrc_template));
505 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
507 "Demultiplex a QuickTime file into audio and video streams",
508 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
510 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
515 gst_qtdemux_init (GstQTDemux * qtdemux)
518 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
519 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
520 gst_pad_set_activatemode_function (qtdemux->sinkpad,
521 qtdemux_sink_activate_mode);
522 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
523 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
524 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
526 qtdemux->state = QTDEMUX_STATE_INITIAL;
527 qtdemux->pullbased = FALSE;
528 qtdemux->posted_redirect = FALSE;
529 qtdemux->neededbytes = 16;
531 qtdemux->adapter = gst_adapter_new ();
533 qtdemux->first_mdat = -1;
534 qtdemux->got_moov = FALSE;
535 qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
536 qtdemux->mdatbuffer = NULL;
537 qtdemux->restoredata_buffer = NULL;
538 qtdemux->restoredata_offset = GST_CLOCK_TIME_NONE;
539 qtdemux->fragment_start = -1;
540 qtdemux->fragment_start_offset = -1;
541 qtdemux->media_caps = NULL;
542 qtdemux->exposed = FALSE;
543 qtdemux->mss_mode = FALSE;
544 qtdemux->pending_newsegment = NULL;
545 qtdemux->upstream_newsegment = FALSE;
546 qtdemux->have_group_id = FALSE;
547 qtdemux->group_id = G_MAXUINT;
548 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
550 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
554 gst_qtdemux_dispose (GObject * object)
556 GstQTDemux *qtdemux = GST_QTDEMUX (object);
558 if (qtdemux->adapter) {
559 g_object_unref (G_OBJECT (qtdemux->adapter));
560 qtdemux->adapter = NULL;
563 G_OBJECT_CLASS (parent_class)->dispose (object);
567 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
569 if (qtdemux->posted_redirect) {
570 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
571 (_("This file contains no playable streams.")),
572 ("no known streams found, a redirect message has been posted"));
574 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
575 (_("This file contains no playable streams.")),
576 ("no known streams found"));
581 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
583 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
584 mem, size, 0, size, mem, free_func);
588 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
595 if (G_UNLIKELY (size == 0)) {
597 GstBuffer *tmp = NULL;
599 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
600 if (ret != GST_FLOW_OK)
603 gst_buffer_map (tmp, &map, GST_MAP_READ);
604 size = QT_UINT32 (map.data);
605 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
607 gst_buffer_unmap (tmp, &map);
608 gst_buffer_unref (tmp);
611 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
612 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
613 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
614 /* we're pulling header but already got most interesting bits,
615 * so never mind the rest (e.g. tags) (that much) */
616 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
620 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
621 (_("This file is invalid and cannot be played.")),
622 ("atom has bogus size %" G_GUINT64_FORMAT, size));
623 return GST_FLOW_ERROR;
627 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
629 if (G_UNLIKELY (flow != GST_FLOW_OK))
632 bsize = gst_buffer_get_size (*buf);
633 /* Catch short reads - we don't want any partial atoms */
634 if (G_UNLIKELY (bsize < size)) {
635 GST_WARNING_OBJECT (qtdemux,
636 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
637 gst_buffer_unref (*buf);
647 gst_qtdemux_src_convert (GstPad * pad, GstFormat src_format, gint64 src_value,
648 GstFormat dest_format, gint64 * dest_value)
651 QtDemuxStream *stream = gst_pad_get_element_private (pad);
652 GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
655 if (stream->subtype != FOURCC_vide) {
660 switch (src_format) {
661 case GST_FORMAT_TIME:
662 switch (dest_format) {
663 case GST_FORMAT_BYTES:{
664 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
668 *dest_value = stream->samples[index].offset;
670 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
671 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
672 GST_TIME_ARGS (src_value), *dest_value);
680 case GST_FORMAT_BYTES:
681 switch (dest_format) {
682 case GST_FORMAT_TIME:{
684 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
691 gst_util_uint64_scale (stream->samples[index].timestamp,
692 GST_SECOND, stream->timescale);
693 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Offset->Time :%"
694 G_GUINT64_FORMAT "->%" GST_TIME_FORMAT,
695 src_value, GST_TIME_ARGS (*dest_value));
708 gst_object_unref (qtdemux);
715 gst_qtdemux_get_duration (GstQTDemux * qtdemux, gint64 * duration)
719 *duration = GST_CLOCK_TIME_NONE;
721 if (qtdemux->duration != 0) {
722 if (qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
723 *duration = gst_util_uint64_scale (qtdemux->duration,
724 GST_SECOND, qtdemux->timescale);
731 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
734 gboolean res = FALSE;
735 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
737 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
739 switch (GST_QUERY_TYPE (query)) {
740 case GST_QUERY_POSITION:{
743 gst_query_parse_position (query, &fmt, NULL);
744 if (fmt == GST_FORMAT_TIME
745 && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
746 gst_query_set_position (query, GST_FORMAT_TIME,
747 qtdemux->segment.position);
752 case GST_QUERY_DURATION:{
755 gst_query_parse_duration (query, &fmt, NULL);
756 if (fmt == GST_FORMAT_TIME) {
757 /* First try to query upstream */
758 res = gst_pad_query_default (pad, parent, query);
760 gint64 duration = -1;
761 gst_qtdemux_get_duration (qtdemux, &duration);
763 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
770 case GST_QUERY_CONVERT:{
771 GstFormat src_fmt, dest_fmt;
772 gint64 src_value, dest_value = 0;
774 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
776 res = gst_qtdemux_src_convert (pad,
777 src_fmt, src_value, dest_fmt, &dest_value);
779 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
784 case GST_QUERY_FORMATS:
785 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
788 case GST_QUERY_SEEKING:{
792 /* try upstream first */
793 res = gst_pad_query_default (pad, parent, query);
796 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
797 if (fmt == GST_FORMAT_TIME) {
798 gint64 duration = -1;
800 gst_qtdemux_get_duration (qtdemux, &duration);
802 if (!qtdemux->pullbased) {
805 /* we might be able with help from upstream */
807 q = gst_query_new_seeking (GST_FORMAT_BYTES);
808 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
809 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
810 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
814 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
820 case GST_QUERY_SEGMENT:
825 format = qtdemux->segment.format;
828 gst_segment_to_stream_time (&qtdemux->segment, format,
829 qtdemux->segment.start);
830 if ((stop = qtdemux->segment.stop) == -1)
831 stop = qtdemux->segment.duration;
833 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
835 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
840 res = gst_pad_query_default (pad, parent, query);
848 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
850 if (G_LIKELY (stream->pad)) {
851 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
852 GST_DEBUG_PAD_NAME (stream->pad));
854 if (G_UNLIKELY (stream->pending_tags)) {
855 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
856 stream->pending_tags);
857 gst_pad_push_event (stream->pad,
858 gst_event_new_tag (stream->pending_tags));
859 stream->pending_tags = NULL;
862 if (G_UNLIKELY (stream->send_global_tags && qtdemux->tag_list)) {
863 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
865 gst_pad_push_event (stream->pad,
866 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
867 stream->send_global_tags = FALSE;
872 /* push event on all source pads; takes ownership of the event */
874 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
877 gboolean has_valid_stream = FALSE;
878 GstEventType etype = GST_EVENT_TYPE (event);
880 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
881 GST_EVENT_TYPE_NAME (event));
883 for (n = 0; n < qtdemux->n_streams; n++) {
885 QtDemuxStream *stream = qtdemux->streams[n];
886 GST_DEBUG_OBJECT (qtdemux, "pushing on pad %i", n);
888 if ((pad = stream->pad)) {
889 has_valid_stream = TRUE;
891 if (etype == GST_EVENT_EOS) {
892 /* let's not send twice */
893 if (stream->sent_eos)
895 stream->sent_eos = TRUE;
898 gst_pad_push_event (pad, gst_event_ref (event));
902 gst_event_unref (event);
904 /* if it is EOS and there are no pads, post an error */
905 if (!has_valid_stream && etype == GST_EVENT_EOS) {
906 gst_qtdemux_post_no_playable_stream_error (qtdemux);
910 /* push a pending newsegment event, if any from the streaming thread */
912 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
914 if (qtdemux->pending_newsegment) {
915 gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
916 qtdemux->pending_newsegment = NULL;
926 find_func (QtDemuxSample * s1, guint64 * media_time, gpointer user_data)
928 if (s1->timestamp > *media_time)
934 /* find the index of the sample that includes the data for @media_time using a
935 * binary search. Only to be called in optimized cases of linear search below.
937 * Returns the index of the sample.
940 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
943 QtDemuxSample *result;
946 /* convert media_time to mov format */
948 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
950 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
951 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
952 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
954 if (G_LIKELY (result))
955 index = result - str->samples;
964 /* find the index of the sample that includes the data for @media_offset using a
967 * Returns the index of the sample.
970 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
971 QtDemuxStream * str, gint64 media_offset)
973 QtDemuxSample *result = str->samples;
976 if (result == NULL || str->n_samples == 0)
979 if (media_offset == result->offset)
983 while (index < str->n_samples - 1) {
984 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
987 if (media_offset < result->offset)
998 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1003 /* find the index of the sample that includes the data for @media_time using a
1004 * linear search, and keeping in mind that not all samples may have been parsed
1005 * yet. If possible, it will delegate to binary search.
1007 * Returns the index of the sample.
1010 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
1016 /* convert media_time to mov format */
1018 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1020 if (mov_time == str->samples[0].timestamp)
1023 /* use faster search if requested time in already parsed range */
1024 if (str->stbl_index >= 0 &&
1025 mov_time <= str->samples[str->stbl_index].timestamp)
1026 return gst_qtdemux_find_index (qtdemux, str, media_time);
1028 while (index < str->n_samples - 1) {
1029 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1032 if (mov_time < str->samples[index + 1].timestamp)
1042 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1047 /* find the index of the keyframe needed to decode the sample at @index
1050 * Returns the index of the keyframe.
1053 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1056 guint32 new_index = index;
1058 if (index >= str->n_samples) {
1059 new_index = str->n_samples;
1063 /* all keyframes, return index */
1064 if (str->all_keyframe) {
1069 /* else go back until we have a keyframe */
1071 if (str->samples[new_index].keyframe)
1081 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index before index %u "
1082 "gave %u", index, new_index);
1087 /* find the segment for @time_position for @stream
1089 * Returns -1 if the segment cannot be found.
1092 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1093 guint64 time_position)
1098 GST_LOG_OBJECT (qtdemux, "finding segment for %" GST_TIME_FORMAT,
1099 GST_TIME_ARGS (time_position));
1101 /* find segment corresponding to time_position if we are looking
1104 for (i = 0; i < stream->n_segments; i++) {
1105 QtDemuxSegment *segment = &stream->segments[i];
1107 GST_LOG_OBJECT (qtdemux,
1108 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1109 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1111 /* For the last segment we include stop_time in the last segment */
1112 if (i < stream->n_segments - 1) {
1113 if (segment->time <= time_position && time_position < segment->stop_time) {
1114 GST_LOG_OBJECT (qtdemux, "segment %d matches", i);
1119 if (segment->time <= time_position && time_position <= segment->stop_time) {
1120 GST_LOG_OBJECT (qtdemux, "segment %d matches", i);
1129 /* move the stream @str to the sample position @index.
1131 * Updates @str->sample_index and marks discontinuity if needed.
1134 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1137 /* no change needed */
1138 if (index == str->sample_index)
1141 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1144 /* position changed, we have a discont */
1145 str->sample_index = index;
1146 str->offset_in_sample = 0;
1147 /* Each time we move in the stream we store the position where we are
1149 str->from_sample = index;
1150 str->discont = TRUE;
1154 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1155 gint64 * key_time, gint64 * key_offset)
1158 gint64 min_byte_offset = -1;
1161 min_offset = desired_time;
1163 /* for each stream, find the index of the sample in the segment
1164 * and move back to the previous keyframe. */
1165 for (n = 0; n < qtdemux->n_streams; n++) {
1167 guint32 index, kindex;
1169 guint64 media_start;
1172 QtDemuxSegment *seg;
1174 str = qtdemux->streams[n];
1176 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1177 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1179 /* segment not found, continue with normal flow */
1183 /* get segment and time in the segment */
1184 seg = &str->segments[seg_idx];
1185 seg_time = desired_time - seg->time;
1187 /* get the media time in the segment */
1188 media_start = seg->media_start + seg_time;
1190 /* get the index of the sample with media time */
1191 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1192 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1193 " at offset %" G_GUINT64_FORMAT,
1194 GST_TIME_ARGS (media_start), index, str->samples[index].offset);
1196 /* find previous keyframe */
1197 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index);
1199 /* if the keyframe is at a different position, we need to update the
1200 * requested seek time */
1201 if (index != kindex) {
1204 /* get timestamp of keyframe */
1206 gst_util_uint64_scale (str->samples[kindex].timestamp, GST_SECOND,
1208 GST_DEBUG_OBJECT (qtdemux, "keyframe at %u with time %" GST_TIME_FORMAT
1209 " at offset %" G_GUINT64_FORMAT,
1210 kindex, GST_TIME_ARGS (media_time), str->samples[kindex].offset);
1212 /* keyframes in the segment get a chance to change the
1213 * desired_offset. keyframes out of the segment are
1215 if (media_time >= seg->media_start) {
1218 /* this keyframe is inside the segment, convert back to
1220 seg_time = (media_time - seg->media_start) + seg->time;
1221 if (seg_time < min_offset)
1222 min_offset = seg_time;
1226 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1227 min_byte_offset = str->samples[index].offset;
1231 *key_time = min_offset;
1233 *key_offset = min_byte_offset;
1237 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1238 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1242 g_return_val_if_fail (format != NULL, FALSE);
1243 g_return_val_if_fail (cur != NULL, FALSE);
1244 g_return_val_if_fail (stop != NULL, FALSE);
1246 if (*format == GST_FORMAT_TIME)
1250 if (cur_type != GST_SEEK_TYPE_NONE)
1251 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1252 if (res && stop_type != GST_SEEK_TYPE_NONE)
1253 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1256 *format = GST_FORMAT_TIME;
1261 /* perform seek in push based mode:
1262 find BYTE position to move to based on time and delegate to upstream
1265 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1270 GstSeekType cur_type, stop_type;
1271 gint64 cur, stop, key_cur;
1274 gint64 original_stop;
1277 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1279 gst_event_parse_seek (event, &rate, &format, &flags,
1280 &cur_type, &cur, &stop_type, &stop);
1281 seqnum = gst_event_get_seqnum (event);
1283 /* only forward streaming and seeking is possible */
1285 goto unsupported_seek;
1287 /* convert to TIME if needed and possible */
1288 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1292 /* Upstrea seek in bytes will have undefined stop, but qtdemux stores
1293 * the original stop position to use when upstream pushes the new segment
1295 original_stop = stop;
1298 /* find reasonable corresponding BYTE position,
1299 * also try to mind about keyframes, since we can not go back a bit for them
1301 gst_qtdemux_adjust_seek (qtdemux, cur, &key_cur, &byte_cur);
1306 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1307 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1310 GST_OBJECT_LOCK (qtdemux);
1311 qtdemux->seek_offset = byte_cur;
1312 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1313 qtdemux->push_seek_start = cur;
1315 qtdemux->push_seek_start = key_cur;
1318 if (stop_type == GST_SEEK_TYPE_NONE) {
1319 qtdemux->push_seek_stop = qtdemux->segment.stop;
1321 qtdemux->push_seek_stop = original_stop;
1323 GST_OBJECT_UNLOCK (qtdemux);
1325 /* BYTE seek event */
1326 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1328 gst_event_set_seqnum (event, seqnum);
1329 res = gst_pad_push_event (qtdemux->sinkpad, event);
1336 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1342 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1347 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1352 /* perform the seek.
1354 * We set all segment_indexes in the streams to unknown and
1355 * adjust the time_position to the desired position. this is enough
1356 * to trigger a segment switch in the streaming thread to start
1357 * streaming from the desired position.
1359 * Keyframe seeking is a little more complicated when dealing with
1360 * segments. Ideally we want to move to the previous keyframe in
1361 * the segment but there might not be a keyframe in the segment. In
1362 * fact, none of the segments could contain a keyframe. We take a
1363 * practical approach: seek to the previous keyframe in the segment,
1364 * if there is none, seek to the beginning of the segment.
1366 * Called with STREAM_LOCK
1369 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1372 gint64 desired_offset;
1375 desired_offset = segment->position;
1377 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1378 GST_TIME_ARGS (desired_offset));
1380 /* may not have enough fragmented info to do this adjustment,
1381 * and we can't scan (and probably should not) at this time with
1382 * possibly flushing upstream */
1383 if ((segment->flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1386 gst_qtdemux_adjust_seek (qtdemux, desired_offset, &min_offset, NULL);
1387 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1388 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1389 desired_offset = min_offset;
1392 /* and set all streams to the final position */
1393 for (n = 0; n < qtdemux->n_streams; n++) {
1394 QtDemuxStream *stream = qtdemux->streams[n];
1396 stream->time_position = desired_offset;
1397 stream->sample_index = -1;
1398 stream->offset_in_sample = 0;
1399 stream->segment_index = -1;
1400 stream->last_ret = GST_FLOW_OK;
1401 stream->sent_eos = FALSE;
1402 stream->segment_seqnum = seqnum;
1404 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1405 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1407 segment->position = desired_offset;
1408 segment->time = desired_offset;
1409 qtdemux->segment_base = desired_offset;
1411 /* we stop at the end */
1412 if (segment->stop == -1)
1413 segment->stop = segment->duration;
1418 /* do a seek in pull based mode */
1420 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1425 GstSeekType cur_type, stop_type;
1429 GstSegment seeksegment;
1432 GstEvent *flush_event;
1435 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1437 gst_event_parse_seek (event, &rate, &format, &flags,
1438 &cur_type, &cur, &stop_type, &stop);
1439 seqnum = gst_event_get_seqnum (event);
1441 /* we have to have a format as the segment format. Try to convert
1443 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1447 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1449 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1453 flush = flags & GST_SEEK_FLAG_FLUSH;
1455 /* stop streaming, either by flushing or by pausing the task */
1457 flush_event = gst_event_new_flush_start ();
1459 gst_event_set_seqnum (flush_event, seqnum);
1460 /* unlock upstream pull_range */
1461 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1462 /* make sure out loop function exits */
1463 gst_qtdemux_push_event (qtdemux, flush_event);
1465 /* non flushing seek, pause the task */
1466 gst_pad_pause_task (qtdemux->sinkpad);
1469 /* wait for streaming to finish */
1470 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1472 /* copy segment, we need this because we still need the old
1473 * segment when we close the current segment. */
1474 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1477 /* configure the segment with the seek variables */
1478 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1479 gst_segment_do_seek (&seeksegment, rate, format, flags,
1480 cur_type, cur, stop_type, stop, &update);
1483 /* now do the seek, this actually never returns FALSE */
1484 gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum);
1486 /* prepare for streaming again */
1488 flush_event = gst_event_new_flush_stop (TRUE);
1490 gst_event_set_seqnum (flush_event, seqnum);
1492 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1493 gst_qtdemux_push_event (qtdemux, flush_event);
1496 /* commit the new segment */
1497 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1499 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1500 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1501 qtdemux->segment.format, qtdemux->segment.position);
1503 gst_message_set_seqnum (msg, seqnum);
1504 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1507 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1508 for (i = 0; i < qtdemux->n_streams; i++)
1509 qtdemux->streams[i]->last_ret = GST_FLOW_OK;
1511 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1512 qtdemux->sinkpad, NULL);
1514 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1521 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1527 qtdemux_ensure_index (GstQTDemux * qtdemux)
1531 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1533 /* Build complete index */
1534 for (i = 0; i < qtdemux->n_streams; i++) {
1535 QtDemuxStream *stream = qtdemux->streams[i];
1537 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1545 GST_LOG_OBJECT (qtdemux,
1546 "Building complete index of stream %u for seeking failed!", i);
1552 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1555 gboolean res = TRUE;
1556 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1558 switch (GST_EVENT_TYPE (event)) {
1559 case GST_EVENT_SEEK:
1561 #ifndef GST_DISABLE_GST_DEBUG
1562 GstClockTime ts = gst_util_get_timestamp ();
1565 if (qtdemux->upstream_newsegment || qtdemux->fragmented) {
1566 /* seek should be handled by upstream, we might need to re-download fragments */
1567 GST_DEBUG_OBJECT (qtdemux,
1568 "leting upstream handle seek for smoothstreaming");
1572 /* Build complete index for seeking;
1573 * if not a fragmented file at least */
1574 if (!qtdemux->fragmented)
1575 if (!qtdemux_ensure_index (qtdemux))
1577 #ifndef GST_DISABLE_GST_DEBUG
1578 ts = gst_util_get_timestamp () - ts;
1579 GST_INFO_OBJECT (qtdemux,
1580 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1583 if (qtdemux->pullbased) {
1584 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1585 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1586 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1588 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams
1589 && !qtdemux->fragmented) {
1590 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1592 GST_DEBUG_OBJECT (qtdemux,
1593 "ignoring seek in push mode in current state");
1596 gst_event_unref (event);
1599 case GST_EVENT_NAVIGATION:
1601 gst_event_unref (event);
1605 res = gst_pad_event_default (pad, parent, event);
1615 GST_ERROR_OBJECT (qtdemux, "Index failed");
1616 gst_event_unref (event);
1622 /* stream/index return sample that is min/max w.r.t. byte position,
1623 * time is min/max w.r.t. time of samples,
1624 * the latter need not be time of the former sample */
1626 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1627 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1630 gint64 time, min_time;
1631 QtDemuxStream *stream;
1637 for (n = 0; n < qtdemux->n_streams; ++n) {
1640 gboolean set_sample;
1642 str = qtdemux->streams[n];
1649 i = str->n_samples - 1;
1653 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1654 if (str->samples[i].size == 0)
1657 if (fw && (str->samples[i].offset < byte_pos))
1660 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1663 /* move stream to first available sample */
1665 gst_qtdemux_move_stream (qtdemux, str, i);
1669 /* avoid index from sparse streams since they might be far away */
1671 /* determine min/max time */
1672 time = str->samples[i].timestamp + str->samples[i].pts_offset;
1673 time = gst_util_uint64_scale (time, GST_SECOND, str->timescale);
1674 if (min_time == -1 || (!fw && time > min_time) ||
1675 (fw && time < min_time)) {
1679 /* determine stream with leading sample, to get its position */
1681 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1682 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1690 /* no sample for this stream, mark eos */
1692 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1703 static QtDemuxStream *
1704 _create_stream (void)
1706 QtDemuxStream *stream;
1708 stream = g_new0 (QtDemuxStream, 1);
1709 /* new streams always need a discont */
1710 stream->discont = TRUE;
1711 /* we enable clipping for raw audio/video streams */
1712 stream->need_clip = FALSE;
1713 stream->need_process = FALSE;
1714 stream->segment_index = -1;
1715 stream->time_position = 0;
1716 stream->sample_index = -1;
1717 stream->offset_in_sample = 0;
1718 stream->last_ret = GST_FLOW_OK;
1719 stream->new_stream = TRUE;
1724 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1726 GstStructure *structure;
1727 const gchar *variant;
1728 const GstCaps *mediacaps = NULL;
1730 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1732 structure = gst_caps_get_structure (caps, 0);
1733 variant = gst_structure_get_string (structure, "variant");
1735 if (variant && strcmp (variant, "mss-fragmented") == 0) {
1736 QtDemuxStream *stream;
1737 const GValue *value;
1739 demux->fragmented = TRUE;
1740 demux->mss_mode = TRUE;
1742 if (demux->n_streams > 1) {
1743 /* can't do this, we can only renegotiate for another mss format */
1747 value = gst_structure_get_value (structure, "media-caps");
1750 const GValue *timescale_v;
1752 /* TODO update when stream changes during playback */
1754 if (demux->n_streams == 0) {
1755 stream = _create_stream ();
1756 demux->streams[demux->n_streams] = stream;
1757 demux->n_streams = 1;
1759 stream = demux->streams[0];
1762 timescale_v = gst_structure_get_value (structure, "timescale");
1764 stream->timescale = g_value_get_uint64 (timescale_v);
1766 /* default mss timescale */
1767 stream->timescale = 10000000;
1769 demux->timescale = stream->timescale;
1771 mediacaps = gst_value_get_caps (value);
1772 if (!stream->caps || !gst_caps_is_equal_fixed (mediacaps, stream->caps)) {
1773 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1775 stream->new_caps = TRUE;
1777 gst_caps_replace (&stream->caps, (GstCaps *) mediacaps);
1778 structure = gst_caps_get_structure (mediacaps, 0);
1779 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
1780 stream->subtype = FOURCC_vide;
1782 gst_structure_get_int (structure, "width", &stream->width);
1783 gst_structure_get_int (structure, "height", &stream->height);
1784 gst_structure_get_fraction (structure, "framerate", &stream->fps_n,
1786 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
1788 stream->subtype = FOURCC_soun;
1789 gst_structure_get_int (structure, "channels", &stream->n_channels);
1790 gst_structure_get_int (structure, "rate", &rate);
1791 stream->rate = rate;
1794 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
1796 demux->mss_mode = FALSE;
1803 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
1807 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
1808 gst_pad_stop_task (qtdemux->sinkpad);
1810 if (hard || qtdemux->upstream_newsegment) {
1811 qtdemux->state = QTDEMUX_STATE_INITIAL;
1812 qtdemux->neededbytes = 16;
1813 qtdemux->todrop = 0;
1814 qtdemux->pullbased = FALSE;
1815 qtdemux->posted_redirect = FALSE;
1816 qtdemux->first_mdat = -1;
1817 qtdemux->header_size = 0;
1818 qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
1819 qtdemux->restoredata_offset = GST_CLOCK_TIME_NONE;
1820 if (qtdemux->mdatbuffer)
1821 gst_buffer_unref (qtdemux->mdatbuffer);
1822 if (qtdemux->restoredata_buffer)
1823 gst_buffer_unref (qtdemux->restoredata_buffer);
1824 qtdemux->mdatbuffer = NULL;
1825 qtdemux->restoredata_buffer = NULL;
1826 qtdemux->mdatleft = 0;
1827 if (qtdemux->comp_brands)
1828 gst_buffer_unref (qtdemux->comp_brands);
1829 qtdemux->comp_brands = NULL;
1830 qtdemux->last_moov_offset = -1;
1831 if (qtdemux->moov_node)
1832 g_node_destroy (qtdemux->moov_node);
1833 qtdemux->moov_node = NULL;
1834 qtdemux->moov_node_compressed = NULL;
1835 if (qtdemux->tag_list)
1836 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
1837 qtdemux->tag_list = NULL;
1839 if (qtdemux->element_index)
1840 gst_object_unref (qtdemux->element_index);
1841 qtdemux->element_index = NULL;
1843 qtdemux->major_brand = 0;
1844 if (qtdemux->pending_newsegment)
1845 gst_event_unref (qtdemux->pending_newsegment);
1846 qtdemux->pending_newsegment = NULL;
1847 qtdemux->upstream_newsegment = FALSE;
1848 qtdemux->upstream_seekable = FALSE;
1849 qtdemux->upstream_size = 0;
1851 qtdemux->fragment_start = -1;
1852 qtdemux->fragment_start_offset = -1;
1853 qtdemux->duration = 0;
1854 qtdemux->mfra_offset = 0;
1855 qtdemux->moof_offset = 0;
1856 qtdemux->chapters_track_id = 0;
1857 qtdemux->have_group_id = FALSE;
1858 qtdemux->group_id = G_MAXUINT;
1860 qtdemux->offset = 0;
1861 gst_adapter_clear (qtdemux->adapter);
1862 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
1863 qtdemux->segment_base = 0;
1866 for (n = 0; n < qtdemux->n_streams; n++) {
1867 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
1868 qtdemux->streams[n] = NULL;
1870 qtdemux->n_streams = 0;
1871 qtdemux->n_video_streams = 0;
1872 qtdemux->n_audio_streams = 0;
1873 qtdemux->n_sub_streams = 0;
1874 qtdemux->exposed = FALSE;
1875 qtdemux->fragmented = FALSE;
1876 qtdemux->mss_mode = FALSE;
1877 gst_caps_replace (&qtdemux->media_caps, NULL);
1878 qtdemux->timescale = 0;
1879 qtdemux->got_moov = FALSE;
1880 } else if (qtdemux->mss_mode) {
1881 for (n = 0; n < qtdemux->n_streams; n++)
1882 gst_qtdemux_stream_clear (qtdemux->streams[n]);
1884 for (n = 0; n < qtdemux->n_streams; n++) {
1885 qtdemux->streams[n]->last_ret = GST_FLOW_OK;
1886 qtdemux->streams[n]->sent_eos = FALSE;
1887 qtdemux->streams[n]->segment_seqnum = 0;
1888 qtdemux->streams[n]->time_position = 0;
1894 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
1897 GstQTDemux *demux = GST_QTDEMUX (parent);
1898 gboolean res = TRUE;
1900 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
1902 switch (GST_EVENT_TYPE (event)) {
1903 case GST_EVENT_SEGMENT:
1906 QtDemuxStream *stream;
1909 GstEvent *segment_event;
1911 /* some debug output */
1912 gst_event_copy_segment (event, &segment);
1913 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
1916 if (segment.format == GST_FORMAT_TIME) {
1917 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
1918 gst_event_replace (&demux->pending_newsegment, event);
1919 demux->upstream_newsegment = TRUE;
1921 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
1922 "not in time format");
1924 /* chain will send initial newsegment after pads have been added */
1925 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
1926 GST_DEBUG_OBJECT (demux, "still starting, eating event");
1931 /* check if this matches a time seek we received previously
1932 * FIXME for backwards compatibility reasons we use the
1933 * seek_offset here to compare. In the future we might want to
1934 * change this to use the seqnum as it uniquely should identify
1935 * the segment that corresponds to the seek. */
1936 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
1937 ", received segment offset %" G_GINT64_FORMAT,
1938 demux->seek_offset, segment.start);
1939 if (segment.format == GST_FORMAT_BYTES
1940 && demux->seek_offset == segment.start) {
1941 GST_OBJECT_LOCK (demux);
1942 offset = segment.start;
1944 segment.format = GST_FORMAT_TIME;
1945 segment.start = demux->push_seek_start;
1946 segment.stop = demux->push_seek_stop;
1947 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
1948 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
1949 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
1950 GST_OBJECT_UNLOCK (demux);
1953 /* we only expect a BYTE segment, e.g. following a seek */
1954 if (segment.format == GST_FORMAT_BYTES) {
1955 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
1956 offset = segment.start;
1958 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
1959 NULL, (gint64 *) & segment.start);
1960 if ((gint64) segment.start < 0)
1963 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
1964 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
1965 NULL, (gint64 *) & segment.stop);
1966 /* keyframe seeking should already arrange for start >= stop,
1967 * but make sure in other rare cases */
1968 segment.stop = MAX (segment.stop, segment.start);
1970 } else if (segment.format == GST_FORMAT_TIME) {
1973 gst_qtdemux_push_event (demux, gst_event_ref (event));
1974 gst_event_new_new_segment_full (segment.update, segment.rate,
1975 segment.arate, GST_FORMAT_TIME, segment.start, segment.stop,
1977 gst_adapter_clear (demux->adapter);
1978 demux->neededbytes = 16;
1982 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
1986 /* accept upstream's notion of segment and distribute along */
1987 segment.format = GST_FORMAT_TIME;
1988 segment.position = segment.time = segment.start;
1989 segment.duration = demux->segment.duration;
1990 segment.base = gst_segment_to_running_time (&demux->segment,
1991 GST_FORMAT_TIME, demux->segment.position);
1993 gst_segment_copy_into (&segment, &demux->segment);
1994 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
1995 segment_event = gst_event_new_segment (&segment);
1996 gst_event_set_seqnum (segment_event, gst_event_get_seqnum (event));
1997 gst_qtdemux_push_event (demux, segment_event);
1999 /* clear leftover in current segment, if any */
2000 gst_adapter_clear (demux->adapter);
2001 /* set up streaming thread */
2002 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx, NULL);
2003 demux->offset = offset;
2005 demux->todrop = stream->samples[idx].offset - offset;
2006 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2008 /* set up for EOS */
2009 if (demux->upstream_newsegment) {
2010 demux->neededbytes = 16;
2012 demux->neededbytes = -1;
2017 gst_event_unref (event);
2022 case GST_EVENT_FLUSH_STOP:
2026 dur = demux->segment.duration;
2027 gst_qtdemux_reset (demux, FALSE);
2028 demux->segment.duration = dur;
2032 /* If we are in push mode, and get an EOS before we've seen any streams,
2033 * then error out - we have nowhere to send the EOS */
2034 if (!demux->pullbased) {
2036 gboolean has_valid_stream = FALSE;
2037 for (i = 0; i < demux->n_streams; i++) {
2038 if (demux->streams[i]->pad != NULL) {
2039 has_valid_stream = TRUE;
2043 if (!has_valid_stream)
2044 gst_qtdemux_post_no_playable_stream_error (demux);
2046 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2047 (guint) gst_adapter_available (demux->adapter));
2048 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2054 case GST_EVENT_CAPS:{
2055 GstCaps *caps = NULL;
2057 gst_event_parse_caps (event, &caps);
2058 gst_qtdemux_setcaps (demux, caps);
2060 gst_event_unref (event);
2068 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2076 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2078 GstQTDemux *demux = GST_QTDEMUX (element);
2080 GST_OBJECT_LOCK (demux);
2081 if (demux->element_index)
2082 gst_object_unref (demux->element_index);
2084 demux->element_index = gst_object_ref (index);
2086 demux->element_index = NULL;
2088 GST_OBJECT_UNLOCK (demux);
2089 /* object lock might be taken again */
2091 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2092 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2093 demux->element_index, demux->index_id);
2097 gst_qtdemux_get_index (GstElement * element)
2099 GstIndex *result = NULL;
2100 GstQTDemux *demux = GST_QTDEMUX (element);
2102 GST_OBJECT_LOCK (demux);
2103 if (demux->element_index)
2104 result = gst_object_ref (demux->element_index);
2105 GST_OBJECT_UNLOCK (demux);
2107 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2114 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2116 g_free ((gpointer) stream->stco.data);
2117 stream->stco.data = NULL;
2118 g_free ((gpointer) stream->stsz.data);
2119 stream->stsz.data = NULL;
2120 g_free ((gpointer) stream->stsc.data);
2121 stream->stsc.data = NULL;
2122 g_free ((gpointer) stream->stts.data);
2123 stream->stts.data = NULL;
2124 g_free ((gpointer) stream->stss.data);
2125 stream->stss.data = NULL;
2126 g_free ((gpointer) stream->stps.data);
2127 stream->stps.data = NULL;
2128 g_free ((gpointer) stream->ctts.data);
2129 stream->ctts.data = NULL;
2133 gst_qtdemux_stream_clear (QtDemuxStream * stream)
2135 if (stream->allocator)
2136 gst_object_unref (stream->allocator);
2137 while (stream->buffers) {
2138 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2139 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2141 if (stream->rgb8_palette) {
2142 gst_memory_unref (stream->rgb8_palette);
2143 stream->rgb8_palette = NULL;
2145 g_free (stream->samples);
2146 stream->samples = NULL;
2147 g_free (stream->segments);
2148 stream->segments = NULL;
2149 if (stream->pending_tags)
2150 gst_tag_list_unref (stream->pending_tags);
2151 stream->pending_tags = NULL;
2152 g_free (stream->redirect_uri);
2153 stream->redirect_uri = NULL;
2154 /* free stbl sub-atoms */
2155 gst_qtdemux_stbl_free (stream);
2157 stream->last_ret = GST_FLOW_OK;
2158 stream->sent_eos = FALSE;
2159 stream->segment_index = -1;
2160 stream->time_position = 0;
2161 stream->sample_index = -1;
2162 stream->stbl_index = -1;
2163 stream->n_samples = 0;
2164 stream->sparse = FALSE;
2168 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
2170 gst_qtdemux_stream_clear (stream);
2172 gst_caps_unref (stream->caps);
2173 stream->caps = NULL;
2175 gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
2180 gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int i)
2182 g_assert (i >= 0 && i < qtdemux->n_streams && qtdemux->streams[i] != NULL);
2184 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[i]);
2185 qtdemux->streams[i] = qtdemux->streams[qtdemux->n_streams - 1];
2186 qtdemux->streams[qtdemux->n_streams - 1] = NULL;
2187 qtdemux->n_streams--;
2190 static GstStateChangeReturn
2191 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2193 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2194 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2196 switch (transition) {
2197 case GST_STATE_CHANGE_PAUSED_TO_READY:
2203 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2205 switch (transition) {
2206 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2207 gst_qtdemux_reset (qtdemux, TRUE);
2218 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2220 /* counts as header data */
2221 qtdemux->header_size += length;
2223 /* only consider at least a sufficiently complete ftyp atom */
2227 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2228 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2229 GST_FOURCC_ARGS (qtdemux->major_brand));
2230 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2231 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2236 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist)
2238 /* Strip out bogus fields */
2240 gst_tag_list_remove_tag (taglist, GST_TAG_VIDEO_CODEC);
2242 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, taglist);
2244 if (qtdemux->tag_list) {
2245 /* prioritize native tags using _KEEP mode */
2246 gst_tag_list_insert (qtdemux->tag_list, taglist, GST_TAG_MERGE_KEEP);
2247 gst_tag_list_unref (taglist);
2249 qtdemux->tag_list = taglist;
2254 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2256 static guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2257 0x97, 0xA9, 0x42, 0xE8,
2258 0x9C, 0x71, 0x99, 0x94,
2259 0x91, 0xE3, 0xAF, 0xAC
2261 static guint8 playready_uuid[] = {
2262 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2263 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2267 /* counts as header data */
2268 qtdemux->header_size += length;
2270 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2272 if (length <= offset + 16) {
2273 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2277 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2279 GstTagList *taglist;
2281 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2282 length - offset - 16, NULL);
2283 taglist = gst_tag_list_from_xmp_buffer (buf);
2284 gst_buffer_unref (buf);
2286 qtdemux_handle_xmp_taglist (qtdemux, taglist);
2288 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
2290 const gunichar2 *s_utf16;
2293 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
2294 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
2295 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
2296 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
2300 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
2301 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
2304 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
2305 GST_READ_UINT32_LE (buffer + offset),
2306 GST_READ_UINT32_LE (buffer + offset + 4),
2307 GST_READ_UINT32_LE (buffer + offset + 8),
2308 GST_READ_UINT32_LE (buffer + offset + 12));
2312 /* caller verifies at least 8 bytes in buf */
2314 extract_initial_length_and_fourcc (const guint8 * data, guint size,
2315 guint64 * plength, guint32 * pfourcc)
2320 length = QT_UINT32 (data);
2321 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2322 fourcc = QT_FOURCC (data + 4);
2323 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
2326 length = G_MAXUINT32;
2327 } else if (length == 1 && size >= 16) {
2328 /* this means we have an extended size, which is the 64 bit value of
2329 * the next 8 bytes */
2330 length = QT_UINT64 (data + 8);
2331 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2341 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
2343 guint32 version = 0;
2344 guint64 duration = 0;
2346 if (!gst_byte_reader_get_uint32_be (br, &version))
2351 if (!gst_byte_reader_get_uint64_be (br, &duration))
2356 if (!gst_byte_reader_get_uint32_be (br, &dur))
2361 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
2362 qtdemux->duration = duration;
2368 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
2374 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
2375 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
2377 if (!stream->parsed_trex && qtdemux->moov_node) {
2379 GstByteReader trex_data;
2381 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
2383 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
2386 guint32 id = 0, dur = 0, size = 0, flags = 0, dummy = 0;
2388 /* skip version/flags */
2389 if (!gst_byte_reader_skip (&trex_data, 4))
2391 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
2393 if (id != stream->track_id)
2395 /* sample description index; ignore */
2396 if (!gst_byte_reader_get_uint32_be (&trex_data, &dummy))
2398 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2400 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
2402 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
2405 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
2406 "duration %d, size %d, flags 0x%x", stream->track_id,
2409 stream->parsed_trex = TRUE;
2410 stream->def_sample_duration = dur;
2411 stream->def_sample_size = size;
2412 stream->def_sample_flags = flags;
2415 /* iterate all siblings */
2416 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
2422 *ds_duration = stream->def_sample_duration;
2423 *ds_size = stream->def_sample_size;
2424 *ds_flags = stream->def_sample_flags;
2426 /* even then, above values are better than random ... */
2427 if (G_UNLIKELY (!stream->parsed_trex)) {
2428 GST_WARNING_OBJECT (qtdemux,
2429 "failed to find fragment defaults for stream %d", stream->track_id);
2437 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
2438 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
2439 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
2440 gint64 * base_offset, gint64 * running_offset)
2443 gint32 data_offset = 0;
2444 guint32 flags = 0, first_flags = 0, samples_count = 0;
2447 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
2448 QtDemuxSample *sample;
2449 gboolean ismv = FALSE;
2451 GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
2452 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT,
2453 stream->track_id, d_sample_duration, d_sample_size, d_sample_flags,
2456 /* presence of stss or not can't really tell us much,
2457 * and flags and so on tend to be marginally reliable in these files */
2458 if (stream->subtype == FOURCC_soun) {
2459 GST_DEBUG_OBJECT (qtdemux,
2460 "sound track in fragmented file; marking all keyframes");
2461 stream->all_keyframe = TRUE;
2464 if (!gst_byte_reader_skip (trun, 1) ||
2465 !gst_byte_reader_get_uint24_be (trun, &flags))
2468 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
2471 if (flags & TR_DATA_OFFSET) {
2472 /* note this is really signed */
2473 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
2475 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
2476 /* default base offset = first byte of moof */
2477 if (*base_offset == -1) {
2478 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
2479 *base_offset = moof_offset;
2481 *running_offset = *base_offset + data_offset;
2483 /* if no offset at all, that would mean data starts at moof start,
2484 * which is a bit wrong and is ismv crappy way, so compensate
2485 * assuming data is in mdat following moof */
2486 if (*base_offset == -1) {
2487 *base_offset = moof_offset + moof_length + 8;
2488 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
2491 if (*running_offset == -1)
2492 *running_offset = *base_offset;
2495 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
2497 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
2498 data_offset, flags, samples_count);
2500 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2501 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
2502 GST_DEBUG_OBJECT (qtdemux,
2503 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
2504 flags ^= TR_FIRST_SAMPLE_FLAGS;
2506 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
2508 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
2512 /* FIXME ? spec says other bits should also be checked to determine
2513 * entry size (and prefix size for that matter) */
2515 dur_offset = size_offset = 0;
2516 if (flags & TR_SAMPLE_DURATION) {
2517 GST_LOG_OBJECT (qtdemux, "entry duration present");
2518 dur_offset = entry_size;
2521 if (flags & TR_SAMPLE_SIZE) {
2522 GST_LOG_OBJECT (qtdemux, "entry size present");
2523 size_offset = entry_size;
2526 if (flags & TR_SAMPLE_FLAGS) {
2527 GST_LOG_OBJECT (qtdemux, "entry flags present");
2528 flags_offset = entry_size;
2531 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2532 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
2533 ct_offset = entry_size;
2537 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
2539 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
2541 if (stream->n_samples >=
2542 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
2545 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
2546 stream->n_samples, (guint) sizeof (QtDemuxSample),
2547 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
2549 /* create a new array of samples if it's the first sample parsed */
2550 if (stream->n_samples == 0)
2551 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
2552 /* or try to reallocate it with space enough to insert the new samples */
2554 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
2555 stream->n_samples + samples_count);
2556 if (stream->samples == NULL)
2559 if (qtdemux->fragment_start != -1) {
2560 timestamp = gst_util_uint64_scale_int (qtdemux->fragment_start,
2561 stream->timescale, GST_SECOND);
2562 qtdemux->fragment_start = -1;
2564 if (G_UNLIKELY (stream->n_samples == 0)) {
2565 /* the timestamp of the first sample is also provided by the tfra entry
2566 * but we shouldn't rely on it as it is at the end of files */
2569 /* subsequent fragments extend stream */
2571 stream->samples[stream->n_samples - 1].timestamp +
2572 stream->samples[stream->n_samples - 1].duration;
2575 sample = stream->samples + stream->n_samples;
2576 for (i = 0; i < samples_count; i++) {
2577 guint32 dur, size, sflags, ct;
2579 /* first read sample data */
2580 if (flags & TR_SAMPLE_DURATION) {
2581 dur = QT_UINT32 (data + dur_offset);
2583 dur = d_sample_duration;
2585 if (flags & TR_SAMPLE_SIZE) {
2586 size = QT_UINT32 (data + size_offset);
2588 size = d_sample_size;
2590 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2592 sflags = first_flags;
2594 sflags = d_sample_flags;
2596 } else if (flags & TR_SAMPLE_FLAGS) {
2597 sflags = QT_UINT32 (data + flags_offset);
2599 sflags = d_sample_flags;
2601 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2602 ct = QT_UINT32 (data + ct_offset);
2608 /* fill the sample information */
2609 sample->offset = *running_offset;
2610 sample->pts_offset = ct;
2611 sample->size = size;
2612 sample->timestamp = timestamp;
2613 sample->duration = dur;
2614 /* sample-is-difference-sample */
2615 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
2616 * now idea how it relates to bitfield other than massive LE/BE confusion */
2617 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
2618 *running_offset += size;
2623 stream->n_samples += samples_count;
2629 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
2634 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
2640 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
2641 "be larger than %uMB (broken file?)", stream->n_samples,
2642 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
2647 /* find stream with @id */
2648 static inline QtDemuxStream *
2649 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
2651 QtDemuxStream *stream;
2655 if (G_UNLIKELY (!id)) {
2656 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
2660 /* try to get it fast and simple */
2661 if (G_LIKELY (id <= qtdemux->n_streams)) {
2662 stream = qtdemux->streams[id - 1];
2663 if (G_LIKELY (stream->track_id == id))
2667 /* linear search otherwise */
2668 for (i = 0; i < qtdemux->n_streams; i++) {
2669 stream = qtdemux->streams[i];
2670 if (stream->track_id == id)
2673 if (qtdemux->mss_mode) {
2674 /* mss should have only 1 stream anyway */
2675 return qtdemux->streams[0];
2682 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
2683 QtDemuxStream ** stream, guint32 * default_sample_duration,
2684 guint32 * default_sample_size, guint32 * default_sample_flags,
2685 gint64 * base_offset)
2688 guint32 track_id = 0;
2690 if (!gst_byte_reader_skip (tfhd, 1) ||
2691 !gst_byte_reader_get_uint24_be (tfhd, &flags))
2694 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
2697 *stream = qtdemux_find_stream (qtdemux, track_id);
2698 if (G_UNLIKELY (!*stream))
2699 goto unknown_stream;
2701 if (flags & TF_BASE_DATA_OFFSET)
2702 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
2705 /* obtain stream defaults */
2706 qtdemux_parse_trex (qtdemux, *stream,
2707 default_sample_duration, default_sample_size, default_sample_flags);
2709 /* FIXME: Handle TF_SAMPLE_DESCRIPTION_INDEX properly */
2710 if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
2711 if (!gst_byte_reader_skip (tfhd, 4))
2714 if (flags & TF_DEFAULT_SAMPLE_DURATION)
2715 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
2718 if (flags & TF_DEFAULT_SAMPLE_SIZE)
2719 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
2722 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
2723 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
2730 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
2735 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
2741 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
2742 guint64 * decode_time)
2744 guint32 version = 0;
2746 if (!gst_byte_reader_get_uint32_be (br, &version))
2751 if (!gst_byte_reader_get_uint64_be (br, decode_time))
2754 guint32 dec_time = 0;
2755 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
2757 *decode_time = dec_time;
2760 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
2767 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
2773 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
2774 guint64 moof_offset, QtDemuxStream * stream)
2776 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node;
2777 GstByteReader trun_data, tfhd_data, tfdt_data;
2778 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
2779 gint64 base_offset, running_offset;
2781 /* NOTE @stream ignored */
2783 moof_node = g_node_new ((guint8 *) buffer);
2784 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
2785 qtdemux_node_dump (qtdemux, moof_node);
2787 /* unknown base_offset to start with */
2788 base_offset = running_offset = -1;
2789 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
2791 /* Fragment Header node */
2793 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
2797 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
2798 &ds_size, &ds_flags, &base_offset))
2801 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
2804 guint64 decode_time = 0;
2805 GstClockTime decode_time_ts;
2807 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
2809 /* FIXME, we can use decode_time to interpolate timestamps
2810 * in case the input timestamps are missing */
2811 decode_time_ts = gst_util_uint64_scale (decode_time, GST_SECOND,
2814 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GUINT64_FORMAT
2815 " (%" GST_TIME_FORMAT ")", decode_time,
2816 GST_TIME_ARGS (decode_time_ts));
2819 if (G_UNLIKELY (!stream)) {
2820 /* we lost track of offset, we'll need to regain it,
2821 * but can delay complaining until later or avoid doing so altogether */
2825 if (G_UNLIKELY (base_offset < -1))
2827 /* Track Run node */
2829 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
2832 qtdemux_parse_trun (qtdemux, &trun_data, stream,
2833 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
2835 /* iterate all siblings */
2836 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
2839 /* if no new base_offset provided for next traf,
2840 * base is end of current traf */
2841 base_offset = running_offset;
2842 running_offset = -1;
2844 /* iterate all siblings */
2845 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
2847 g_node_destroy (moof_node);
2852 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
2857 GST_DEBUG_OBJECT (qtdemux, "lost offset");
2862 g_node_destroy (moof_node);
2863 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
2864 (_("This file is corrupt and cannot be played.")), (NULL));
2869 /* might be used if some day we actually use mfra & co
2870 * for random access to fragments,
2871 * but that will require quite some modifications and much less relying
2872 * on a sample array */
2875 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node,
2876 QtDemuxStream * stream)
2878 guint64 time = 0, moof_offset = 0;
2879 guint32 ver_flags, track_id, len, num_entries, i;
2880 guint value_size, traf_size, trun_size, sample_size;
2881 GstBuffer *buf = NULL;
2885 gst_byte_reader_init (&tfra, (guint8 *) tfra_node->data + (4 + 4),
2886 QT_UINT32 ((guint8 *) tfra_node->data) - (4 + 4));
2888 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
2891 if (!(gst_byte_reader_get_uint32_be (&tfra, &track_id) &&
2892 gst_byte_reader_get_uint32_be (&tfra, &len) &&
2893 gst_byte_reader_get_uint32_be (&tfra, &num_entries)))
2896 GST_LOG_OBJECT (qtdemux, "id %d == stream id %d ?",
2897 track_id, stream->track_id);
2898 if (track_id != stream->track_id) {
2902 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
2903 sample_size = (len & 3) + 1;
2904 trun_size = ((len & 12) >> 2) + 1;
2905 traf_size = ((len & 48) >> 4) + 1;
2907 if (num_entries == 0)
2910 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
2911 value_size + value_size + traf_size + trun_size + sample_size))
2914 for (i = 0; i < num_entries; i++) {
2915 qt_atom_parser_get_offset (&tfra, value_size, &time);
2916 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
2917 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
2918 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
2919 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
2921 GST_LOG_OBJECT (qtdemux,
2922 "fragment time: %" GST_TIME_FORMAT " moof_offset: %u",
2923 GST_TIME_ARGS (gst_util_uint64_scale (time, GST_SECOND,
2924 stream->timescale)), moof_offset);
2926 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
2927 if (ret != GST_FLOW_OK)
2929 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
2930 moof_offset, stream);
2931 gst_buffer_unref (buf);
2939 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
2940 (_("This file is corrupt and cannot be played.")), (NULL));
2945 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
2951 qtdemux_parse_mfra (GstQTDemux * qtdemux, QtDemuxStream * stream)
2954 GNode *mfra_node, *tfra_node;
2957 if (!qtdemux->mfra_offset)
2960 ret = gst_qtdemux_pull_atom (qtdemux, qtdemux->mfra_offset, 0, &buffer);
2961 if (ret != GST_FLOW_OK)
2964 mfra_node = g_node_new ((guint8 *) GST_BUFFER_DATA (buffer));
2965 qtdemux_parse_node (qtdemux, mfra_node, GST_BUFFER_DATA (buffer),
2966 GST_BUFFER_SIZE (buffer));
2968 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
2971 qtdemux_parse_tfra (qtdemux, tfra_node, stream);
2972 /* iterate all siblings */
2973 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
2975 g_node_destroy (mfra_node);
2976 gst_buffer_unref (buffer);
2982 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
2983 (_("This file is corrupt and cannot be played.")), (NULL));
2988 static GstFlowReturn
2989 qtdemux_parse_mfro (GstQTDemux * qtdemux, guint64 * mfra_offset,
2990 guint32 * mfro_size)
2992 GstFlowReturn ret = GST_FLOW_ERROR;
2993 GstBuffer *mfro = NULL;
2996 GstFormat fmt = GST_FORMAT_BYTES;
2998 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, &fmt, &len)) {
2999 GST_DEBUG_OBJECT (qtdemux, "upstream size not available; "
3000 "can not locate mfro");
3004 ret = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
3005 if (ret != GST_FLOW_OK)
3008 fourcc = QT_FOURCC (GST_BUFFER_DATA (mfro) + 4);
3009 if (fourcc != FOURCC_mfro)
3012 GST_INFO_OBJECT (qtdemux, "Found mfro atom: fragmented mp4 container");
3013 if (GST_BUFFER_SIZE (mfro) >= 16) {
3014 GST_DEBUG_OBJECT (qtdemux, "parsing 'mfro' atom");
3015 *mfro_size = QT_UINT32 (GST_BUFFER_DATA (mfro) + 12);
3016 if (*mfro_size >= len) {
3017 GST_WARNING_OBJECT (qtdemux, "mfro.size is invalid");
3018 ret = GST_FLOW_ERROR;
3021 *mfra_offset = len - *mfro_size;
3026 gst_buffer_unref (mfro);
3032 qtdemux_parse_fragmented (GstQTDemux * qtdemux)
3035 guint32 mfra_size = 0;
3036 guint64 mfra_offset = 0;
3039 qtdemux->fragmented = FALSE;
3041 /* We check here if it is a fragmented mp4 container */
3042 ret = qtdemux_parse_mfro (qtdemux, &mfra_offset, &mfra_size);
3043 if (ret == GST_FLOW_OK && mfra_size != 0 && mfra_offset != 0) {
3044 qtdemux->fragmented = TRUE;
3045 GST_DEBUG_OBJECT (qtdemux,
3046 "mfra atom expected at offset %" G_GUINT64_FORMAT, mfra_offset);
3047 qtdemux->mfra_offset = mfra_offset;
3052 static GstFlowReturn
3053 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
3057 GstBuffer *buf = NULL;
3058 GstFlowReturn ret = GST_FLOW_OK;
3059 guint64 cur_offset = qtdemux->offset;
3062 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
3063 if (G_UNLIKELY (ret != GST_FLOW_OK))
3065 gst_buffer_map (buf, &map, GST_MAP_READ);
3066 if (G_LIKELY (map.size >= 8))
3067 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
3068 gst_buffer_unmap (buf, &map);
3069 gst_buffer_unref (buf);
3071 /* maybe we already got most we needed, so only consider this eof */
3072 if (G_UNLIKELY (length == 0)) {
3073 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
3074 (_("Invalid atom size.")),
3075 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
3076 GST_FOURCC_ARGS (fourcc)));
3083 /* record for later parsing when needed */
3084 if (!qtdemux->moof_offset) {
3085 qtdemux->moof_offset = qtdemux->offset;
3094 GST_LOG_OBJECT (qtdemux,
3095 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
3096 GST_FOURCC_ARGS (fourcc), cur_offset);
3097 qtdemux->offset += length;
3102 GstBuffer *moov = NULL;
3104 if (qtdemux->got_moov) {
3105 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
3106 qtdemux->offset += length;
3110 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
3111 if (ret != GST_FLOW_OK)
3113 gst_buffer_map (moov, &map, GST_MAP_READ);
3115 if (length != map.size) {
3116 /* Some files have a 'moov' atom at the end of the file which contains
3117 * a terminal 'free' atom where the body of the atom is missing.
3118 * Check for, and permit, this special case.
3120 if (map.size >= 8) {
3121 guint8 *final_data = map.data + (map.size - 8);
3122 guint32 final_length = QT_UINT32 (final_data);
3123 guint32 final_fourcc = QT_FOURCC (final_data + 4);
3125 if (final_fourcc == FOURCC_free
3126 && map.size + final_length - 8 == length) {
3127 /* Ok, we've found that special case. Allocate a new buffer with
3128 * that free atom actually present. */
3129 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
3130 gst_buffer_fill (newmoov, 0, map.data, map.size);
3131 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
3132 gst_buffer_unmap (moov, &map);
3133 gst_buffer_unref (moov);
3135 gst_buffer_map (moov, &map, GST_MAP_READ);
3140 if (length != map.size) {
3141 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
3142 (_("This file is incomplete and cannot be played.")),
3143 ("We got less than expected (received %" G_GSIZE_FORMAT
3144 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
3145 (guint) length, cur_offset));
3146 gst_buffer_unmap (moov, &map);
3147 gst_buffer_unref (moov);
3148 ret = GST_FLOW_ERROR;
3151 qtdemux->offset += length;
3153 qtdemux_parse_moov (qtdemux, map.data, length);
3154 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
3156 qtdemux_parse_tree (qtdemux);
3157 g_node_destroy (qtdemux->moov_node);
3158 gst_buffer_unmap (moov, &map);
3159 gst_buffer_unref (moov);
3160 qtdemux->moov_node = NULL;
3161 qtdemux->got_moov = TRUE;
3167 GstBuffer *ftyp = NULL;
3169 /* extract major brand; might come in handy for ISO vs QT issues */
3170 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
3171 if (ret != GST_FLOW_OK)
3173 qtdemux->offset += length;
3174 gst_buffer_map (ftyp, &map, GST_MAP_READ);
3175 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
3176 gst_buffer_unmap (ftyp, &map);
3177 gst_buffer_unref (ftyp);
3182 GstBuffer *uuid = NULL;
3184 /* uuid are extension atoms */
3185 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
3186 if (ret != GST_FLOW_OK)
3188 qtdemux->offset += length;
3189 gst_buffer_map (uuid, &map, GST_MAP_READ);
3190 qtdemux_parse_uuid (qtdemux, map.data, map.size);
3191 gst_buffer_unmap (uuid, &map);
3192 gst_buffer_unref (uuid);
3197 GstBuffer *unknown = NULL;
3199 GST_LOG_OBJECT (qtdemux,
3200 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
3201 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
3203 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
3204 if (ret != GST_FLOW_OK)
3206 gst_buffer_map (unknown, &map, GST_MAP_READ);
3207 GST_MEMDUMP ("Unknown tag", map.data, map.size);
3208 gst_buffer_unmap (unknown, &map);
3209 gst_buffer_unref (unknown);
3210 qtdemux->offset += length;
3216 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
3217 /* digested all data, show what we have */
3218 qtdemux_prepare_streams (qtdemux);
3219 ret = qtdemux_expose_streams (qtdemux);
3221 qtdemux->state = QTDEMUX_STATE_MOVIE;
3222 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
3229 /* Seeks to the previous keyframe of the indexed stream and
3230 * aligns other streams with respect to the keyframe timestamp
3231 * of indexed stream. Only called in case of Reverse Playback
3233 static GstFlowReturn
3234 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
3237 guint32 seg_idx = 0, k_index = 0;
3238 guint32 ref_seg_idx, ref_k_index;
3239 guint64 k_pos = 0, last_stop = 0;
3240 QtDemuxSegment *seg = NULL;
3241 QtDemuxStream *ref_str = NULL;
3242 guint64 seg_media_start_mov; /* segment media start time in mov format */
3244 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
3245 * and finally align all the other streams on that timestamp with their
3246 * respective keyframes */
3247 for (n = 0; n < qtdemux->n_streams; n++) {
3248 QtDemuxStream *str = qtdemux->streams[n];
3250 seg_idx = gst_qtdemux_find_segment (qtdemux, str,
3251 qtdemux->segment.position);
3253 /* segment not found, continue with normal flow */
3257 /* No candidate yet, take that one */
3263 /* So that stream has a segment, we prefer video streams */
3264 if (str->subtype == FOURCC_vide) {
3270 if (G_UNLIKELY (!ref_str)) {
3271 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
3275 if (G_UNLIKELY (!ref_str->from_sample)) {
3276 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
3280 /* So that stream has been playing from from_sample to to_sample. We will
3281 * get the timestamp of the previous sample and search for a keyframe before
3282 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
3283 if (ref_str->subtype == FOURCC_vide) {
3284 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
3285 ref_str->from_sample - 1);
3287 if (ref_str->from_sample >= 10)
3288 k_index = ref_str->from_sample - 10;
3293 /* get current segment for that stream */
3294 seg = &ref_str->segments[ref_str->segment_index];
3295 /* convert seg->media_start to mov format time for timestamp comparison */
3296 seg_media_start_mov =
3297 gst_util_uint64_scale (seg->media_start, ref_str->timescale, GST_SECOND);
3298 /* Crawl back through segments to find the one containing this I frame */
3299 while (ref_str->samples[k_index].timestamp < seg_media_start_mov) {
3300 GST_DEBUG_OBJECT (qtdemux, "keyframe position is out of segment %u",
3301 ref_str->segment_index);
3302 if (G_UNLIKELY (!ref_str->segment_index)) {
3303 /* Reached first segment, let's consider it's EOS */
3306 ref_str->segment_index--;
3307 seg = &ref_str->segments[ref_str->segment_index];
3308 /* convert seg->media_start to mov format time for timestamp comparison */
3309 seg_media_start_mov =
3310 gst_util_uint64_scale (seg->media_start, ref_str->timescale,
3313 /* Calculate time position of the keyframe and where we should stop */
3315 (gst_util_uint64_scale (ref_str->samples[k_index].timestamp, GST_SECOND,
3316 ref_str->timescale) - seg->media_start) + seg->time;
3318 gst_util_uint64_scale (ref_str->samples[ref_str->from_sample].timestamp,
3319 GST_SECOND, ref_str->timescale);
3320 last_stop = (last_stop - seg->media_start) + seg->time;
3322 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
3323 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
3324 k_index, GST_TIME_ARGS (k_pos));
3326 /* Set last_stop with the keyframe timestamp we pushed of that stream */
3327 qtdemux->segment.position = last_stop;
3328 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
3329 GST_TIME_ARGS (last_stop));
3331 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
3332 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
3336 ref_seg_idx = ref_str->segment_index;
3337 ref_k_index = k_index;
3339 /* Align them all on this */
3340 for (n = 0; n < qtdemux->n_streams; n++) {
3342 guint64 media_start = 0, seg_time = 0;
3343 QtDemuxStream *str = qtdemux->streams[n];
3345 /* aligning reference stream again might lead to backing up to yet another
3346 * keyframe (due to timestamp rounding issues),
3347 * potentially putting more load on downstream; so let's try to avoid */
3348 if (str == ref_str) {
3349 seg_idx = ref_seg_idx;
3350 seg = &str->segments[seg_idx];
3351 k_index = ref_k_index;
3352 GST_DEBUG_OBJECT (qtdemux, "reference stream segment %d, "
3353 "sample at index %d", ref_str->segment_index, k_index);
3355 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
3356 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
3358 /* segment not found, continue with normal flow */
3362 /* get segment and time in the segment */
3363 seg = &str->segments[seg_idx];
3364 seg_time = k_pos - seg->time;
3366 /* get the media time in the segment */
3367 media_start = seg->media_start + seg_time;
3369 /* get the index of the sample with media time */
3370 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
3371 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u",
3372 GST_TIME_ARGS (media_start), index);
3374 /* find previous keyframe */
3375 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index);
3378 /* Remember until where we want to go */
3379 str->to_sample = str->from_sample - 1;
3380 /* Define our time position */
3381 str->time_position =
3382 (gst_util_uint64_scale (str->samples[k_index].timestamp, GST_SECOND,
3383 str->timescale) - seg->media_start) + seg->time;
3384 /* Now seek back in time */
3385 gst_qtdemux_move_stream (qtdemux, str, k_index);
3386 GST_DEBUG_OBJECT (qtdemux, "keyframe at %u, time position %"
3387 GST_TIME_FORMAT " playing from sample %u to %u", k_index,
3388 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
3394 return GST_FLOW_EOS;
3397 /* activate the given segment number @seg_idx of @stream at time @offset.
3398 * @offset is an absolute global position over all the segments.
3400 * This will push out a NEWSEGMENT event with the right values and
3401 * position the stream index to the first decodable sample before
3405 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
3406 guint32 seg_idx, guint64 offset)
3409 QtDemuxSegment *segment;
3410 guint32 index, kf_index;
3412 guint64 start, stop, time;
3415 GST_LOG_OBJECT (qtdemux, "activate segment %d, offset %" G_GUINT64_FORMAT,
3418 /* update the current segment */
3419 stream->segment_index = seg_idx;
3421 /* get the segment */
3422 segment = &stream->segments[seg_idx];
3424 if (G_UNLIKELY (offset < segment->time)) {
3425 GST_WARNING_OBJECT (qtdemux, "offset < segment->time %" G_GUINT64_FORMAT,
3430 /* segment lies beyond total indicated duration */
3431 if (G_UNLIKELY (qtdemux->segment.duration != -1 &&
3432 segment->time > qtdemux->segment.duration)) {
3433 GST_WARNING_OBJECT (qtdemux, "file duration %" G_GINT64_FORMAT
3434 " < segment->time %" G_GUINT64_FORMAT, qtdemux->segment.duration,
3439 /* get time in this segment */
3440 seg_time = offset - segment->time;
3442 GST_LOG_OBJECT (qtdemux, "seg_time %" GST_TIME_FORMAT,
3443 GST_TIME_ARGS (seg_time));
3445 if (G_UNLIKELY (seg_time > segment->duration)) {
3446 GST_LOG_OBJECT (qtdemux, "seg_time > segment->duration %" GST_TIME_FORMAT,
3447 GST_TIME_ARGS (segment->duration));
3451 /* qtdemux->segment.stop is in outside-time-realm, whereas
3452 * segment->media_stop is in track-time-realm.
3454 * In order to compare the two, we need to bring segment.stop
3455 * into the track-time-realm */
3457 stop = qtdemux->segment.stop;
3459 stop = qtdemux->segment.duration;
3461 stop = segment->media_stop;
3464 MIN (segment->media_stop, stop - segment->time + segment->media_start);
3466 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
3467 start = segment->time + seg_time;
3469 } else if (qtdemux->segment.rate >= 0) {
3470 start = MIN (segment->media_start + seg_time, stop);
3473 if (segment->media_start >= qtdemux->segment.start) {
3474 start = segment->media_start;
3475 time = segment->time;
3477 start = qtdemux->segment.start;
3478 time = segment->time + (qtdemux->segment.start - segment->media_start);
3481 start = MAX (segment->media_start, qtdemux->segment.start);
3482 stop = MIN (segment->media_start + seg_time, stop);
3485 GST_DEBUG_OBJECT (qtdemux, "newsegment %d from %" GST_TIME_FORMAT
3486 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
3487 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
3489 /* combine global rate with that of the segment */
3490 rate = segment->rate * qtdemux->segment.rate;
3492 /* update the segment values used for clipping */
3493 /* accumulate previous segments */
3494 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
3495 stream->segment.base += (stream->segment.stop - stream->segment.start) /
3496 ABS (stream->segment.rate);
3497 stream->segment.rate = rate;
3498 stream->segment.start = start;
3499 stream->segment.stop = stop;
3500 stream->segment.time = time;
3501 stream->segment.position = start;
3502 stream->segment.base =
3504 qtdemux->segment_base ? segment->time - qtdemux->segment_base : 0;
3506 /* now prepare and send the segment */
3508 event = gst_event_new_segment (&stream->segment);
3509 if (stream->segment_seqnum) {
3510 gst_event_set_seqnum (event, stream->segment_seqnum);
3511 stream->segment_seqnum = 0;
3513 gst_pad_push_event (stream->pad, event);
3514 /* assume we can send more data now */
3515 stream->last_ret = GST_FLOW_OK;
3516 /* clear to send tags on this pad now */
3517 gst_qtdemux_push_tags (qtdemux, stream);
3520 /* and move to the keyframe before the indicated media time of the
3522 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
3523 if (qtdemux->segment.rate >= 0) {
3524 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
3525 stream->to_sample = G_MAXUINT32;
3526 GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
3527 ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
3528 GST_TIME_ARGS (gst_util_uint64_scale (stream->
3529 samples[index].timestamp, GST_SECOND, stream->timescale)));
3531 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
3532 stream->to_sample = index;
3533 GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
3534 ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
3535 GST_TIME_ARGS (gst_util_uint64_scale (stream->
3536 samples[index].timestamp, GST_SECOND, stream->timescale)));
3539 GST_DEBUG_OBJECT (qtdemux, "No need to look for keyframe, "
3540 "this is an empty segment");
3544 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
3545 * encountered an error and printed a message so we return appropriately */
3549 /* we're at the right spot */
3550 if (index == stream->sample_index) {
3551 GST_DEBUG_OBJECT (qtdemux, "we are at the right index");
3555 /* find keyframe of the target index */
3556 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index);
3559 /* indent does stupid stuff with stream->samples[].timestamp */
3561 /* if we move forwards, we don't have to go back to the previous
3562 * keyframe since we already sent that. We can also just jump to
3563 * the keyframe right before the target index if there is one. */
3564 if (index > stream->sample_index) {
3565 /* moving forwards check if we move past a keyframe */
3566 if (kf_index > stream->sample_index) {
3567 GST_DEBUG_OBJECT (qtdemux,
3568 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT, kf_index,
3569 GST_TIME_ARGS (gst_util_uint64_scale (
3570 stream->samples[kf_index].timestamp,
3571 GST_SECOND, stream->timescale)));
3572 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
3574 GST_DEBUG_OBJECT (qtdemux,
3575 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT
3576 " already sent", kf_index,
3577 GST_TIME_ARGS (gst_util_uint64_scale (
3578 stream->samples[kf_index].timestamp,
3579 GST_SECOND, stream->timescale)));
3582 GST_DEBUG_OBJECT (qtdemux,
3583 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT, kf_index,
3584 GST_TIME_ARGS (gst_util_uint64_scale (
3585 stream->samples[kf_index].timestamp,
3586 GST_SECOND, stream->timescale)));
3587 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
3595 /* prepare to get the current sample of @stream, getting essential values.
3597 * This function will also prepare and send the segment when needed.
3599 * Return FALSE if the stream is EOS.
3602 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
3603 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
3604 guint64 * dts, guint64 * pts, guint64 * duration, gboolean * keyframe)
3606 QtDemuxSample *sample;
3607 guint64 time_position;
3610 g_return_val_if_fail (stream != NULL, FALSE);
3612 time_position = stream->time_position;
3613 if (G_UNLIKELY (time_position == -1))
3616 seg_idx = stream->segment_index;
3617 if (G_UNLIKELY (seg_idx == -1)) {
3618 /* find segment corresponding to time_position if we are looking
3620 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
3622 /* nothing found, we're really eos */
3627 /* different segment, activate it, sample_index will be set. */
3628 if (G_UNLIKELY (stream->segment_index != seg_idx))
3629 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
3631 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->
3632 segments[stream->segment_index]))) {
3633 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
3635 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
3636 " prepare empty sample");
3639 *pts = *dts = time_position;
3640 *duration = seg->duration - (time_position - seg->time);
3647 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
3648 stream->sample_index, stream->n_samples);
3650 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
3653 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
3654 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
3655 stream->sample_index);
3659 /* now get the info for the sample we're at */
3660 sample = &stream->samples[stream->sample_index];
3662 *dts = QTSAMPLE_DTS (stream, sample);
3663 *pts = QTSAMPLE_PTS (stream, sample);
3664 *offset = sample->offset;
3665 *size = sample->size;
3666 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
3667 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
3674 stream->time_position = -1;
3679 /* move to the next sample in @stream.
3681 * Moves to the next segment when needed.
3684 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
3686 QtDemuxSample *sample;
3687 QtDemuxSegment *segment;
3689 /* get current segment */
3690 segment = &stream->segments[stream->segment_index];
3692 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
3693 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
3697 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
3698 /* Mark the stream as EOS */
3699 GST_DEBUG_OBJECT (qtdemux,
3700 "reached max allowed sample %u, mark EOS", stream->to_sample);
3701 stream->time_position = -1;
3705 /* move to next sample */
3706 stream->sample_index++;
3707 stream->offset_in_sample = 0;
3709 /* reached the last sample, we need the next segment */
3710 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
3713 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
3714 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
3715 stream->sample_index);
3719 /* get next sample */
3720 sample = &stream->samples[stream->sample_index];
3722 /* see if we are past the segment */
3723 if (G_UNLIKELY (gst_util_uint64_scale (sample->timestamp,
3724 GST_SECOND, stream->timescale) >= segment->media_stop))
3727 if (gst_util_uint64_scale (sample->timestamp, GST_SECOND,
3728 stream->timescale) >= segment->media_start) {
3729 /* inside the segment, update time_position, looks very familiar to
3730 * GStreamer segments, doesn't it? */
3731 stream->time_position =
3732 (gst_util_uint64_scale (sample->timestamp, GST_SECOND,
3733 stream->timescale) - segment->media_start) + segment->time;
3735 /* not yet in segment, time does not yet increment. This means
3736 * that we are still prerolling keyframes to the decoder so it can
3737 * decode the first sample of the segment. */
3738 stream->time_position = segment->time;
3742 /* move to the next segment */
3745 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
3747 if (stream->segment_index == stream->n_segments - 1) {
3748 /* are we at the end of the last segment, we're EOS */
3749 stream->time_position = -1;
3751 /* else we're only at the end of the current segment */
3752 stream->time_position = segment->stop_time;
3754 /* make sure we select a new segment */
3755 stream->segment_index = -1;
3760 gst_qtdemux_sync_streams (GstQTDemux * demux)
3764 if (demux->n_streams <= 1)
3767 for (i = 0; i < demux->n_streams; i++) {
3768 QtDemuxStream *stream;
3769 GstClockTime end_time;
3771 stream = demux->streams[i];
3776 /* TODO advance time on subtitle streams here, if any some day */
3778 /* some clips/trailers may have unbalanced streams at the end,
3779 * so send EOS on shorter stream to prevent stalling others */
3781 /* do not mess with EOS if SEGMENT seeking */
3782 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
3785 if (demux->pullbased) {
3786 /* loop mode is sample time based */
3787 if (!STREAM_IS_EOS (stream))
3790 /* push mode is byte position based */
3791 if (stream->n_samples &&
3792 stream->samples[stream->n_samples - 1].offset >= demux->offset)
3796 if (stream->sent_eos)
3799 /* only act if some gap */
3800 end_time = stream->segments[stream->n_segments - 1].stop_time;
3801 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
3802 ", stream end: %" GST_TIME_FORMAT,
3803 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
3804 if (GST_CLOCK_TIME_IS_VALID (end_time)
3805 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
3806 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
3807 GST_PAD_NAME (stream->pad));
3808 stream->sent_eos = TRUE;
3809 gst_pad_push_event (stream->pad, gst_event_new_eos ());
3814 /* EOS and NOT_LINKED need to be combined. This means that we return:
3816 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
3817 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
3819 static GstFlowReturn
3820 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
3824 gboolean unexpected = FALSE, not_linked = TRUE;
3826 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
3828 /* store the value */
3829 stream->last_ret = ret;
3831 /* any other error that is not-linked or eos can be returned right away */
3832 if (G_LIKELY (ret != GST_FLOW_EOS && ret != GST_FLOW_NOT_LINKED))
3835 /* only return NOT_LINKED if all other pads returned NOT_LINKED */
3836 for (i = 0; i < demux->n_streams; i++) {
3837 QtDemuxStream *ostream = demux->streams[i];
3839 ret = ostream->last_ret;
3841 /* no unexpected or unlinked, return */
3842 if (G_LIKELY (ret != GST_FLOW_EOS && ret != GST_FLOW_NOT_LINKED))
3845 /* we check to see if we have at least 1 unexpected or all unlinked */
3846 unexpected |= (ret == GST_FLOW_EOS);
3847 not_linked &= (ret == GST_FLOW_NOT_LINKED);
3850 /* when we get here, we all have unlinked or unexpected */
3852 ret = GST_FLOW_NOT_LINKED;
3853 else if (unexpected)
3856 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
3860 /* the input buffer metadata must be writable. Returns NULL when the buffer is
3861 * completely clipped
3863 * Should be used only with raw buffers */
3865 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
3868 guint64 start, stop, cstart, cstop, diff;
3869 GstClockTime pts, duration;
3871 gint num_rate, denom_rate;
3876 osize = size = gst_buffer_get_size (buf);
3879 /* depending on the type, setup the clip parameters */
3880 if (stream->subtype == FOURCC_soun) {
3881 frame_size = stream->bytes_per_frame;
3882 num_rate = GST_SECOND;
3883 denom_rate = (gint) stream->rate;
3885 } else if (stream->subtype == FOURCC_vide) {
3887 num_rate = stream->fps_n;
3888 denom_rate = stream->fps_d;
3893 if (frame_size <= 0)
3894 goto bad_frame_size;
3896 /* we can only clip if we have a valid pts */
3897 pts = GST_BUFFER_PTS (buf);
3898 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
3901 duration = GST_BUFFER_DURATION (buf);
3903 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
3905 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
3909 stop = start + duration;
3911 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
3912 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
3915 /* see if some clipping happened */
3916 diff = cstart - start;
3922 /* bring clipped time to samples and to bytes */
3923 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
3926 GST_DEBUG_OBJECT (qtdemux,
3927 "clipping start to %" GST_TIME_FORMAT " %"
3928 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
3934 diff = stop - cstop;
3939 /* bring clipped time to samples and then to bytes */
3940 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
3942 GST_DEBUG_OBJECT (qtdemux,
3943 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
3944 " bytes", GST_TIME_ARGS (cstop), diff);
3949 if (offset != 0 || size != osize)
3950 gst_buffer_resize (buf, offset, size);
3952 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
3953 GST_BUFFER_PTS (buf) = pts;
3954 GST_BUFFER_DURATION (buf) = duration;
3958 /* dropped buffer */
3961 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
3966 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
3971 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
3976 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
3977 gst_buffer_unref (buf);
3982 /* the input buffer metadata must be writable,
3983 * but time/duration etc not yet set and need not be preserved */
3985 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
3992 /* not many cases for now */
3993 if (G_UNLIKELY (stream->fourcc == FOURCC_mp4s)) {
3994 /* send a one time dvd clut event */
3995 if (stream->pending_event && stream->pad)
3996 gst_pad_push_event (stream->pad, stream->pending_event);
3997 stream->pending_event = NULL;
4000 if (G_UNLIKELY (stream->subtype != FOURCC_text
4001 && stream->subtype != FOURCC_sbtl &&
4002 stream->subtype != FOURCC_subp)) {
4006 gst_buffer_map (buf, &map, GST_MAP_READ);
4008 /* empty buffer is sent to terminate previous subtitle */
4009 if (map.size <= 2) {
4010 gst_buffer_unmap (buf, &map);
4011 gst_buffer_unref (buf);
4014 if (stream->subtype == FOURCC_subp) {
4015 /* That's all the processing needed for subpictures */
4016 gst_buffer_unmap (buf, &map);
4020 nsize = GST_READ_UINT16_BE (map.data);
4021 nsize = MIN (nsize, map.size - 2);
4023 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
4026 /* takes care of UTF-8 validation or UTF-16 recognition,
4027 * no other encoding expected */
4028 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
4029 gst_buffer_unmap (buf, &map);
4031 gst_buffer_unref (buf);
4032 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
4034 /* this should not really happen unless the subtitle is corrupted */
4035 gst_buffer_unref (buf);
4039 /* FIXME ? convert optional subsequent style info to markup */
4044 /* Sets a buffer's attributes properly and pushes it downstream.
4045 * Also checks for additional actions and custom processing that may
4046 * need to be done first.
4048 static GstFlowReturn
4049 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
4050 QtDemuxStream * stream, GstBuffer * buf,
4051 guint64 dts, guint64 pts, guint64 duration, gboolean keyframe,
4052 guint64 position, guint64 byte_position)
4054 GstFlowReturn ret = GST_FLOW_OK;
4056 /* offset the timestamps according to the edit list */
4058 if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) {
4062 gst_buffer_map (buf, &map, GST_MAP_READ);
4063 url = g_strndup ((gchar *) map.data, map.size);
4064 gst_buffer_unmap (buf, &map);
4065 if (url != NULL && strlen (url) != 0) {
4066 /* we have RTSP redirect now */
4067 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
4068 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
4069 gst_structure_new ("redirect",
4070 "new-location", G_TYPE_STRING, url, NULL)));
4071 qtdemux->posted_redirect = TRUE;
4073 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
4079 /* position reporting */
4080 if (qtdemux->segment.rate >= 0) {
4081 qtdemux->segment.position = position;
4082 gst_qtdemux_sync_streams (qtdemux);
4085 if (G_UNLIKELY (!stream->pad)) {
4086 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
4087 gst_buffer_unref (buf);
4091 /* send out pending buffers */
4092 while (stream->buffers) {
4093 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
4095 if (G_UNLIKELY (stream->discont)) {
4096 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
4097 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
4098 stream->discont = FALSE;
4100 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
4103 gst_pad_push (stream->pad, buffer);
4105 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
4108 /* we're going to modify the metadata */
4109 buf = gst_buffer_make_writable (buf);
4111 if (G_UNLIKELY (stream->need_process))
4112 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
4118 GST_BUFFER_DTS (buf) = dts;
4119 GST_BUFFER_PTS (buf) = pts;
4120 GST_BUFFER_DURATION (buf) = duration;
4121 GST_BUFFER_OFFSET (buf) = -1;
4122 GST_BUFFER_OFFSET_END (buf) = -1;
4124 if (G_UNLIKELY (stream->rgb8_palette))
4125 gst_buffer_append_memory (buf, gst_memory_ref (stream->rgb8_palette));
4127 if (G_UNLIKELY (stream->padding)) {
4128 gst_buffer_resize (buf, stream->padding, -1);
4131 if (G_UNLIKELY (qtdemux->element_index)) {
4132 GstClockTime stream_time;
4135 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
4137 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
4138 GST_LOG_OBJECT (qtdemux,
4139 "adding association %" GST_TIME_FORMAT "-> %"
4140 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
4141 gst_index_add_association (qtdemux->element_index,
4143 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
4144 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
4145 GST_FORMAT_BYTES, byte_position, NULL);
4150 if (stream->need_clip)
4151 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
4153 if (G_UNLIKELY (buf == NULL))
4156 if (G_UNLIKELY (stream->discont)) {
4157 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
4158 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
4159 stream->discont = FALSE;
4161 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
4165 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
4166 stream->on_keyframe = FALSE;
4168 stream->on_keyframe = TRUE;
4172 GST_LOG_OBJECT (qtdemux,
4173 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
4174 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
4175 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
4176 GST_PAD_NAME (stream->pad));
4178 ret = gst_pad_push (stream->pad, buf);
4180 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
4181 /* mark position in stream, we'll need this to know when to send GAP event */
4182 stream->segment.position = pts + duration;
4189 static GstFlowReturn
4190 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
4192 GstFlowReturn ret = GST_FLOW_OK;
4193 GstBuffer *buf = NULL;
4194 QtDemuxStream *stream;
4197 guint64 dts = GST_CLOCK_TIME_NONE;
4198 guint64 pts = GST_CLOCK_TIME_NONE;
4199 guint64 duration = 0;
4200 gboolean keyframe = FALSE;
4201 guint sample_size = 0;
4207 gst_qtdemux_push_pending_newsegment (qtdemux);
4209 /* Figure out the next stream sample to output, min_time is expressed in
4210 * global time and runs over the edit list segments. */
4211 min_time = G_MAXUINT64;
4213 for (i = 0; i < qtdemux->n_streams; i++) {
4216 stream = qtdemux->streams[i];
4217 position = stream->time_position;
4219 /* position of -1 is EOS */
4220 if (position != -1 && position < min_time) {
4221 min_time = position;
4226 if (G_UNLIKELY (index == -1)) {
4227 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
4231 /* check for segment end */
4232 if (G_UNLIKELY (qtdemux->segment.stop != -1
4233 && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
4234 || (qtdemux->segment.rate < 0
4235 && qtdemux->segment.start > min_time))
4236 && qtdemux->streams[index]->on_keyframe)) {
4237 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
4238 qtdemux->streams[index]->time_position = -1;
4242 /* gap events for subtitle streams */
4243 for (i = 0; i < qtdemux->n_streams; i++) {
4244 stream = qtdemux->streams[i];
4245 if (stream->pad && (stream->subtype == FOURCC_subp
4246 || stream->subtype == FOURCC_text
4247 || stream->subtype == FOURCC_sbtl)) {
4248 /* send one second gap events until the stream catches up */
4249 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
4250 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
4251 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
4252 stream->segment.position + GST_SECOND < min_time) {
4254 gst_event_new_gap (stream->segment.position, GST_SECOND);
4255 gst_pad_push_event (stream->pad, gap);
4256 stream->segment.position += GST_SECOND;
4261 stream = qtdemux->streams[index];
4262 if (stream->new_caps) {
4263 gst_qtdemux_configure_stream (qtdemux, stream);
4264 qtdemux_do_allocation (qtdemux, stream);
4267 /* fetch info for the current sample of this stream */
4268 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
4269 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
4272 GST_DEBUG_OBJECT (qtdemux,
4273 "pushing from stream %d, empty %d offset %" G_GUINT64_FORMAT
4274 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
4275 ", duration %" GST_TIME_FORMAT, index, empty, offset, sample_size,
4276 GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
4278 if (G_UNLIKELY (empty)) {
4279 /* empty segment, push a gap and move to the next one */
4280 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
4281 stream->segment.position = pts + duration;
4285 /* hmm, empty sample, skip and move to next sample */
4286 if (G_UNLIKELY (sample_size <= 0))
4289 /* last pushed sample was out of boundary, goto next sample */
4290 if (G_UNLIKELY (stream->last_ret == GST_FLOW_EOS))
4293 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
4296 GST_DEBUG_OBJECT (qtdemux,
4297 "size %d larger than stream max_buffer_size %d, trimming",
4298 sample_size, stream->max_buffer_size);
4300 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
4303 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
4306 if (stream->use_allocator) {
4307 /* if we have a per-stream allocator, use it */
4308 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
4311 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
4313 if (G_UNLIKELY (ret != GST_FLOW_OK))
4316 if (size != sample_size) {
4317 pts += gst_util_uint64_scale_int (GST_SECOND,
4318 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
4319 dts += gst_util_uint64_scale_int (GST_SECOND,
4320 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
4321 duration = gst_util_uint64_scale_int (GST_SECOND,
4322 size / stream->bytes_per_frame, stream->timescale);
4325 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
4326 dts, pts, duration, keyframe, min_time, offset);
4328 if (size != sample_size) {
4329 QtDemuxSample *sample = &stream->samples[stream->sample_index];
4330 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
4332 GstClockTime time_position = gst_util_uint64_scale (sample->timestamp +
4333 stream->offset_in_sample / stream->bytes_per_frame, GST_SECOND,
4335 if (time_position >= segment->media_start) {
4336 /* inside the segment, update time_position, looks very familiar to
4337 * GStreamer segments, doesn't it? */
4338 stream->time_position = (time_position - segment->media_start) +
4341 /* not yet in segment, time does not yet increment. This means
4342 * that we are still prerolling keyframes to the decoder so it can
4343 * decode the first sample of the segment. */
4344 stream->time_position = segment->time;
4349 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
4350 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
4351 * we have no more data for the pad to push */
4352 if (ret == GST_FLOW_EOS)
4355 stream->offset_in_sample += size;
4356 if (stream->offset_in_sample >= sample_size) {
4357 gst_qtdemux_advance_sample (qtdemux, stream);
4362 gst_qtdemux_advance_sample (qtdemux, stream);
4370 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
4376 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
4377 /* EOS will be raised if all are EOS */
4384 gst_qtdemux_loop (GstPad * pad)
4386 GstQTDemux *qtdemux;
4390 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
4392 cur_offset = qtdemux->offset;
4393 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %d",
4394 cur_offset, qtdemux->state);
4396 switch (qtdemux->state) {
4397 case QTDEMUX_STATE_INITIAL:
4398 case QTDEMUX_STATE_HEADER:
4399 ret = gst_qtdemux_loop_state_header (qtdemux);
4401 case QTDEMUX_STATE_MOVIE:
4402 ret = gst_qtdemux_loop_state_movie (qtdemux);
4403 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
4404 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
4412 /* if something went wrong, pause */
4413 if (ret != GST_FLOW_OK)
4417 gst_object_unref (qtdemux);
4423 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
4424 (NULL), ("streaming stopped, invalid state"));
4425 gst_pad_pause_task (pad);
4426 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
4431 const gchar *reason = gst_flow_get_name (ret);
4433 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
4435 gst_pad_pause_task (pad);
4437 /* fatal errors need special actions */
4439 if (ret == GST_FLOW_EOS) {
4440 if (qtdemux->n_streams == 0) {
4441 /* we have no streams, post an error */
4442 gst_qtdemux_post_no_playable_stream_error (qtdemux);
4444 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
4447 if ((stop = qtdemux->segment.stop) == -1)
4448 stop = qtdemux->segment.duration;
4450 if (qtdemux->segment.rate >= 0) {
4451 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
4452 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
4453 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
4454 GST_FORMAT_TIME, stop));
4455 gst_qtdemux_push_event (qtdemux,
4456 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
4458 /* For Reverse Playback */
4459 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
4460 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
4461 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
4462 GST_FORMAT_TIME, qtdemux->segment.start));
4463 gst_qtdemux_push_event (qtdemux,
4464 gst_event_new_segment_done (GST_FORMAT_TIME,
4465 qtdemux->segment.start));
4468 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
4469 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
4471 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
4472 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
4473 (NULL), ("streaming stopped, reason %s", reason));
4474 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
4483 * Returns if there are samples to be played.
4486 has_next_entry (GstQTDemux * demux)
4488 QtDemuxStream *stream;
4491 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
4493 for (i = 0; i < demux->n_streams; i++) {
4494 stream = demux->streams[i];
4496 if (stream->sample_index == -1) {
4497 stream->sample_index = 0;
4498 stream->offset_in_sample = 0;
4501 if (stream->sample_index >= stream->n_samples) {
4502 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
4505 GST_DEBUG_OBJECT (demux, "Found a sample");
4509 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
4516 * Returns the size of the first entry at the current offset.
4517 * If -1, there are none (which means EOS or empty file).
4520 next_entry_size (GstQTDemux * demux)
4522 QtDemuxStream *stream;
4525 guint64 smalloffs = (guint64) - 1;
4526 QtDemuxSample *sample;
4528 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
4531 for (i = 0; i < demux->n_streams; i++) {
4532 stream = demux->streams[i];
4534 if (stream->sample_index == -1) {
4535 stream->sample_index = 0;
4536 stream->offset_in_sample = 0;
4539 if (stream->sample_index >= stream->n_samples) {
4540 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
4544 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
4545 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
4546 stream->sample_index);
4550 sample = &stream->samples[stream->sample_index];
4552 GST_LOG_OBJECT (demux,
4553 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
4554 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
4555 sample->offset, sample->size);
4557 if (((smalloffs == -1)
4558 || (sample->offset < smalloffs)) && (sample->size)) {
4560 smalloffs = sample->offset;
4564 GST_LOG_OBJECT (demux,
4565 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
4566 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
4571 stream = demux->streams[smallidx];
4572 sample = &stream->samples[stream->sample_index];
4574 if (sample->offset >= demux->offset) {
4575 demux->todrop = sample->offset - demux->offset;
4576 return sample->size + demux->todrop;
4579 GST_DEBUG_OBJECT (demux,
4580 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
4585 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
4587 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
4589 gst_element_post_message (GST_ELEMENT_CAST (demux),
4590 gst_message_new_element (GST_OBJECT_CAST (demux),
4591 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
4595 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
4600 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
4603 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
4604 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
4605 GST_SEEK_TYPE_NONE, -1);
4607 res = gst_pad_push_event (demux->sinkpad, event);
4612 /* check for seekable upstream, above and beyond a mere query */
4614 gst_qtdemux_check_seekability (GstQTDemux * demux)
4617 gboolean seekable = FALSE;
4618 gint64 start = -1, stop = -1;
4620 if (demux->upstream_size)
4623 query = gst_query_new_seeking (GST_FORMAT_BYTES);
4624 if (!gst_pad_peer_query (demux->sinkpad, query)) {
4625 GST_DEBUG_OBJECT (demux, "seeking query failed");
4629 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
4631 /* try harder to query upstream size if we didn't get it the first time */
4632 if (seekable && stop == -1) {
4633 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
4634 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
4637 /* if upstream doesn't know the size, it's likely that it's not seekable in
4638 * practice even if it technically may be seekable */
4639 if (seekable && (start != 0 || stop <= start)) {
4640 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
4645 gst_query_unref (query);
4647 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
4648 G_GUINT64_FORMAT ")", seekable, start, stop);
4649 demux->upstream_seekable = seekable;
4650 demux->upstream_size = seekable ? stop : -1;
4653 /* FIXME, unverified after edit list updates */
4654 static GstFlowReturn
4655 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
4659 demux = GST_QTDEMUX (parent);
4660 gst_adapter_push (demux->adapter, inbuf);
4662 GST_DEBUG_OBJECT (demux,
4663 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
4664 demux->neededbytes, gst_adapter_available (demux->adapter));
4666 return gst_qtdemux_process_adapter (demux, FALSE);
4669 static GstFlowReturn
4670 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
4672 GstFlowReturn ret = GST_FLOW_OK;
4674 /* we never really mean to buffer that much */
4675 if (demux->neededbytes == -1) {
4679 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
4680 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
4682 GST_DEBUG_OBJECT (demux,
4683 "state:%d , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT,
4684 demux->state, demux->neededbytes, demux->offset);
4686 switch (demux->state) {
4687 case QTDEMUX_STATE_INITIAL:{
4692 gst_qtdemux_check_seekability (demux);
4694 data = gst_adapter_map (demux->adapter, demux->neededbytes);
4696 /* get fourcc/length, set neededbytes */
4697 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
4699 gst_adapter_unmap (demux->adapter);
4701 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
4702 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
4704 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4705 (_("This file is invalid and cannot be played.")),
4706 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
4707 GST_FOURCC_ARGS (fourcc)));
4708 ret = GST_FLOW_ERROR;
4711 if (fourcc == FOURCC_mdat) {
4712 gint next_entry = next_entry_size (demux);
4713 if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
4714 /* we have the headers, start playback */
4715 demux->state = QTDEMUX_STATE_MOVIE;
4716 demux->neededbytes = next_entry;
4717 demux->mdatleft = size;
4719 /* no headers yet, try to get them */
4722 guint64 old, target;
4725 old = demux->offset;
4726 target = old + size;
4728 /* try to jump over the atom with a seek */
4729 /* only bother if it seems worth doing so,
4730 * and avoids possible upstream/server problems */
4731 if (demux->upstream_seekable &&
4732 demux->upstream_size > 4 * (1 << 20)) {
4733 res = qtdemux_seek_offset (demux, target);
4735 GST_DEBUG_OBJECT (demux, "skipping seek");
4740 GST_DEBUG_OBJECT (demux, "seek success");
4741 /* remember the offset fo the first mdat so we can seek back to it
4742 * after we have the headers */
4743 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
4744 demux->first_mdat = old;
4745 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
4748 /* seek worked, continue reading */
4749 demux->offset = target;
4750 demux->neededbytes = 16;
4751 demux->state = QTDEMUX_STATE_INITIAL;
4753 /* seek failed, need to buffer */
4754 demux->offset = old;
4755 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
4756 /* there may be multiple mdat (or alike) buffers */
4758 if (demux->mdatbuffer)
4759 bs = gst_buffer_get_size (demux->mdatbuffer);
4762 if (size + bs > 10 * (1 << 20))
4764 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
4765 demux->neededbytes = size;
4766 if (!demux->mdatbuffer)
4767 demux->mdatoffset = demux->offset;
4770 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
4771 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4772 (_("This file is invalid and cannot be played.")),
4773 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
4774 GST_FOURCC_ARGS (fourcc), size));
4775 ret = GST_FLOW_ERROR;
4778 /* this means we already started buffering and still no moov header,
4779 * let's continue buffering everything till we get moov */
4780 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
4781 || fourcc == FOURCC_moof))
4783 demux->neededbytes = size;
4784 demux->state = QTDEMUX_STATE_HEADER;
4788 case QTDEMUX_STATE_HEADER:{
4792 GST_DEBUG_OBJECT (demux, "In header");
4794 data = gst_adapter_map (demux->adapter, demux->neededbytes);
4796 /* parse the header */
4797 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
4799 if (fourcc == FOURCC_moov) {
4800 /* in usual fragmented setup we could try to scan for more
4801 * and end up at the the moov (after mdat) again */
4802 if (demux->got_moov && demux->n_streams > 0 &&
4804 || demux->last_moov_offset == demux->offset)) {
4805 GST_DEBUG_OBJECT (demux,
4806 "Skipping moov atom as we have (this) one already");
4808 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
4810 if (demux->got_moov && demux->fragmented) {
4811 GST_DEBUG_OBJECT (demux,
4812 "Got a second moov, clean up data from old one");
4813 if (demux->moov_node)
4814 g_node_destroy (demux->moov_node);
4815 demux->moov_node = NULL;
4816 demux->moov_node_compressed = NULL;
4818 /* prepare newsegment to send when streaming actually starts */
4819 if (!demux->pending_newsegment)
4820 demux->pending_newsegment =
4821 gst_event_new_segment (&demux->segment);
4824 demux->last_moov_offset = demux->offset;
4826 qtdemux_parse_moov (demux, data, demux->neededbytes);
4827 qtdemux_node_dump (demux, demux->moov_node);
4828 qtdemux_parse_tree (demux);
4829 qtdemux_prepare_streams (demux);
4830 if (!demux->got_moov)
4831 qtdemux_expose_streams (demux);
4835 for (n = 0; n < demux->n_streams; n++) {
4836 QtDemuxStream *stream = demux->streams[n];
4838 gst_qtdemux_configure_stream (demux, stream);
4842 demux->got_moov = TRUE;
4844 g_node_destroy (demux->moov_node);
4845 demux->moov_node = NULL;
4846 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
4848 } else if (fourcc == FOURCC_moof) {
4849 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
4851 GstClockTime prev_pts;
4852 guint64 prev_offset;
4854 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
4857 * The timestamp of the moof buffer is relevant as some scenarios
4858 * won't have the initial timestamp in the atoms. Whenever a new
4859 * buffer has started, we get that buffer's PTS and use it as a base
4860 * timestamp for the trun entries.
4862 * To keep track of the current buffer timestamp and starting point
4863 * we use gst_adapter_prev_pts that gives us the PTS and the distance
4864 * from the beggining of the buffer, with the distance and demux->offset
4865 * we know if it is still the same buffer or not.
4867 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
4868 prev_offset = demux->offset - dist;
4869 if (demux->fragment_start_offset == -1
4870 || prev_offset > demux->fragment_start_offset) {
4871 demux->fragment_start_offset = prev_offset;
4872 demux->fragment_start = prev_pts;
4873 GST_DEBUG_OBJECT (demux,
4874 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
4875 GST_TIME_FORMAT, demux->fragment_start_offset,
4876 GST_TIME_ARGS (demux->fragment_start));
4879 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
4880 demux->offset, NULL)) {
4881 gst_adapter_unmap (demux->adapter);
4882 ret = GST_FLOW_ERROR;
4885 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
4886 if (demux->mss_mode && !demux->exposed) {
4887 if (!demux->pending_newsegment) {
4889 gst_segment_init (&segment, GST_FORMAT_TIME);
4890 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
4891 demux->pending_newsegment = gst_event_new_segment (&segment);
4893 qtdemux_expose_streams (demux);
4896 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
4898 } else if (fourcc == FOURCC_ftyp) {
4899 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
4900 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
4901 } else if (fourcc == FOURCC_uuid) {
4902 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
4903 qtdemux_parse_uuid (demux, data, demux->neededbytes);
4905 GST_WARNING_OBJECT (demux,
4906 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
4907 GST_FOURCC_ARGS (fourcc));
4908 /* Let's jump that one and go back to initial state */
4910 gst_adapter_unmap (demux->adapter);
4913 if (demux->mdatbuffer && demux->n_streams) {
4914 gsize remaining_data_size = 0;
4916 /* the mdat was before the header */
4917 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
4918 demux->n_streams, demux->mdatbuffer);
4919 /* restore our adapter/offset view of things with upstream;
4920 * put preceding buffered data ahead of current moov data.
4921 * This should also handle evil mdat, moov, mdat cases and alike */
4922 gst_adapter_flush (demux->adapter, demux->neededbytes);
4924 /* Store any remaining data after the mdat for later usage */
4925 remaining_data_size = gst_adapter_available (demux->adapter);
4926 if (remaining_data_size > 0) {
4927 g_assert (demux->restoredata_buffer == NULL);
4928 demux->restoredata_buffer =
4929 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
4930 demux->restoredata_offset = demux->offset + demux->neededbytes;
4931 GST_DEBUG_OBJECT (demux,
4932 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
4933 G_GUINT64_FORMAT, remaining_data_size,
4934 demux->restoredata_offset);
4937 gst_adapter_push (demux->adapter, demux->mdatbuffer);
4938 demux->mdatbuffer = NULL;
4939 demux->offset = demux->mdatoffset;
4940 demux->neededbytes = next_entry_size (demux);
4941 demux->state = QTDEMUX_STATE_MOVIE;
4942 demux->mdatleft = gst_adapter_available (demux->adapter);
4944 GST_DEBUG_OBJECT (demux, "Carrying on normally");
4945 gst_adapter_flush (demux->adapter, demux->neededbytes);
4947 /* only go back to the mdat if there are samples to play */
4948 if (demux->got_moov && demux->first_mdat != -1
4949 && has_next_entry (demux)) {
4952 /* we need to seek back */
4953 res = qtdemux_seek_offset (demux, demux->first_mdat);
4955 demux->offset = demux->first_mdat;
4957 GST_DEBUG_OBJECT (demux, "Seek back failed");
4960 demux->offset += demux->neededbytes;
4962 demux->neededbytes = 16;
4963 demux->state = QTDEMUX_STATE_INITIAL;
4968 case QTDEMUX_STATE_BUFFER_MDAT:{
4972 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
4974 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
4975 gst_buffer_extract (buf, 0, fourcc, 4);
4976 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
4977 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
4978 if (demux->mdatbuffer)
4979 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
4981 demux->mdatbuffer = buf;
4982 demux->offset += demux->neededbytes;
4983 demux->neededbytes = 16;
4984 demux->state = QTDEMUX_STATE_INITIAL;
4985 gst_qtdemux_post_progress (demux, 1, 1);
4989 case QTDEMUX_STATE_MOVIE:{
4991 QtDemuxStream *stream = NULL;
4992 QtDemuxSample *sample;
4994 guint64 dts, pts, duration;
4997 GST_DEBUG_OBJECT (demux,
4998 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
5000 if (demux->fragmented) {
5001 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
5003 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
5004 /* if needed data starts within this atom,
5005 * then it should not exceed this atom */
5006 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
5007 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
5008 (_("This file is invalid and cannot be played.")),
5009 ("sample data crosses atom boundary"));
5010 ret = GST_FLOW_ERROR;
5013 demux->mdatleft -= demux->neededbytes;
5015 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
5016 /* so we are dropping more than left in this atom */
5017 demux->todrop -= demux->mdatleft;
5018 demux->neededbytes -= demux->mdatleft;
5019 demux->mdatleft = 0;
5020 /* need to resume atom parsing so we do not miss any other pieces */
5021 demux->state = QTDEMUX_STATE_INITIAL;
5022 demux->neededbytes = 16;
5024 /* check if there was any stored post mdat data from previous buffers */
5025 if (demux->restoredata_buffer) {
5026 g_assert (gst_adapter_available (demux->adapter) == 0);
5028 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
5029 demux->restoredata_buffer = NULL;
5030 demux->offset = demux->restoredata_offset;
5037 if (demux->todrop) {
5038 GST_LOG_OBJECT (demux, "Dropping %d bytes", demux->todrop);
5039 gst_adapter_flush (demux->adapter, demux->todrop);
5040 demux->neededbytes -= demux->todrop;
5041 demux->offset += demux->todrop;
5045 /* initial newsegment sent here after having added pads,
5046 * possible others in sink_event */
5047 if (G_UNLIKELY (demux->pending_newsegment)) {
5048 gst_qtdemux_push_pending_newsegment (demux);
5049 /* clear to send tags on all streams */
5050 for (i = 0; i < demux->n_streams; i++) {
5051 stream = demux->streams[i];
5052 gst_qtdemux_push_tags (demux, stream);
5053 if (stream->sparse) {
5054 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
5055 gst_pad_push_event (stream->pad,
5056 gst_event_new_gap (stream->segment.position,
5057 GST_CLOCK_TIME_NONE));
5062 /* Figure out which stream this packet belongs to */
5063 for (i = 0; i < demux->n_streams; i++) {
5064 stream = demux->streams[i];
5065 if (stream->sample_index >= stream->n_samples)
5067 GST_LOG_OBJECT (demux,
5068 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
5069 " / size:%d)", i, stream->sample_index,
5070 stream->samples[stream->sample_index].offset,
5071 stream->samples[stream->sample_index].size);
5073 if (stream->samples[stream->sample_index].offset == demux->offset)
5077 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
5078 goto unknown_stream;
5080 if (stream->new_caps) {
5081 gst_qtdemux_configure_stream (demux, stream);
5084 /* Put data in a buffer, set timestamps, caps, ... */
5085 sample = &stream->samples[stream->sample_index];
5087 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
5088 outbuf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
5089 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
5090 GST_FOURCC_ARGS (stream->fourcc));
5092 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
5094 dts = QTSAMPLE_DTS (stream, sample);
5095 pts = QTSAMPLE_PTS (stream, sample);
5096 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
5097 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5099 /* check for segment end */
5100 if (G_UNLIKELY (demux->segment.stop != -1
5101 && demux->segment.stop <= pts && stream->on_keyframe)) {
5102 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
5103 stream->time_position = -1; /* this means EOS */
5105 /* check if all streams are eos */
5107 for (i = 0; i < demux->n_streams; i++) {
5108 if (!STREAM_IS_EOS (demux->streams[i])) {
5114 if (ret == GST_FLOW_EOS) {
5115 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
5119 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
5120 dts, pts, duration, keyframe, dts, demux->offset);
5124 ret = gst_qtdemux_combine_flows (demux, stream, ret);
5126 /* skip this data, stream is EOS */
5127 gst_adapter_flush (demux->adapter, demux->neededbytes);
5130 stream->sample_index++;
5131 stream->offset_in_sample = 0;
5133 /* update current offset and figure out size of next buffer */
5134 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
5135 demux->offset, demux->neededbytes);
5136 demux->offset += demux->neededbytes;
5137 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
5140 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
5141 if (demux->fragmented) {
5142 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
5143 /* there may be more to follow, only finish this atom */
5144 demux->todrop = demux->mdatleft;
5145 demux->neededbytes = demux->todrop;
5157 /* when buffering movie data, at least show user something is happening */
5158 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
5159 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
5160 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
5161 demux->neededbytes);
5170 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
5171 ret = GST_FLOW_ERROR;
5176 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
5182 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
5183 (NULL), ("qtdemuxer invalid state %d", demux->state));
5184 ret = GST_FLOW_ERROR;
5189 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
5190 (NULL), ("no 'moov' atom within the first 10 MB"));
5191 ret = GST_FLOW_ERROR;
5197 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
5202 query = gst_query_new_scheduling ();
5204 if (!gst_pad_peer_query (sinkpad, query)) {
5205 gst_query_unref (query);
5209 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
5210 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
5211 gst_query_unref (query);
5216 GST_DEBUG_OBJECT (sinkpad, "activating pull");
5217 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
5221 GST_DEBUG_OBJECT (sinkpad, "activating push");
5222 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
5227 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
5228 GstPadMode mode, gboolean active)
5231 GstQTDemux *demux = GST_QTDEMUX (parent);
5234 case GST_PAD_MODE_PUSH:
5235 demux->pullbased = FALSE;
5238 case GST_PAD_MODE_PULL:
5240 demux->pullbased = TRUE;
5241 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
5244 res = gst_pad_stop_task (sinkpad);
5256 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
5258 return g_malloc (items * size);
5262 qtdemux_zfree (void *opaque, void *addr)
5268 qtdemux_inflate (void *z_buffer, guint z_length, guint length)
5274 z = g_new0 (z_stream, 1);
5275 z->zalloc = qtdemux_zalloc;
5276 z->zfree = qtdemux_zfree;
5279 z->next_in = z_buffer;
5280 z->avail_in = z_length;
5282 buffer = (guint8 *) g_malloc (length);
5283 ret = inflateInit (z);
5284 while (z->avail_in > 0) {
5285 if (z->avail_out == 0) {
5287 buffer = (guint8 *) g_realloc (buffer, length);
5288 z->next_out = buffer + z->total_out;
5289 z->avail_out = 1024;
5291 ret = inflate (z, Z_SYNC_FLUSH);
5295 if (ret != Z_STREAM_END) {
5296 g_warning ("inflate() returned %d", ret);
5302 #endif /* HAVE_ZLIB */
5305 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
5309 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
5311 /* counts as header data */
5312 qtdemux->header_size += length;
5314 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
5315 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
5317 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
5323 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
5324 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
5325 if (dcom == NULL || cmvd == NULL)
5326 goto invalid_compression;
5328 method = QT_FOURCC ((guint8 *) dcom->data + 8);
5331 case GST_MAKE_FOURCC ('z', 'l', 'i', 'b'):{
5332 guint uncompressed_length;
5333 guint compressed_length;
5336 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
5337 compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12;
5338 GST_LOG ("length = %u", uncompressed_length);
5341 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
5342 compressed_length, uncompressed_length);
5344 qtdemux->moov_node_compressed = qtdemux->moov_node;
5345 qtdemux->moov_node = g_node_new (buf);
5347 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
5348 uncompressed_length);
5351 #endif /* HAVE_ZLIB */
5353 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
5354 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
5361 invalid_compression:
5363 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
5369 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
5372 while (G_UNLIKELY (buf < end)) {
5376 if (G_UNLIKELY (buf + 4 > end)) {
5377 GST_LOG_OBJECT (qtdemux, "buffer overrun");
5380 len = QT_UINT32 (buf);
5381 if (G_UNLIKELY (len == 0)) {
5382 GST_LOG_OBJECT (qtdemux, "empty container");
5385 if (G_UNLIKELY (len < 8)) {
5386 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
5389 if (G_UNLIKELY (len > (end - buf))) {
5390 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
5391 (gint) (end - buf));
5395 child = g_node_new ((guint8 *) buf);
5396 g_node_append (node, child);
5397 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
5398 qtdemux_parse_node (qtdemux, child, buf, len);
5406 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
5409 int len = QT_UINT32 (xdxt->data);
5410 guint8 *buf = xdxt->data;
5411 guint8 *end = buf + len;
5414 /* skip size and type */
5422 size = QT_UINT32 (buf);
5423 type = QT_FOURCC (buf + 4);
5425 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
5427 if (buf + size > end || size <= 0)
5433 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
5434 GST_FOURCC_ARGS (type));
5438 buffer = gst_buffer_new_and_alloc (size);
5439 gst_buffer_fill (buffer, 0, buf, size);
5440 stream->buffers = g_slist_append (stream->buffers, buffer);
5441 GST_LOG_OBJECT (qtdemux, "parsing theora header");
5444 buffer = gst_buffer_new_and_alloc (size);
5445 gst_buffer_fill (buffer, 0, buf, size);
5446 stream->buffers = g_slist_append (stream->buffers, buffer);
5447 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
5450 buffer = gst_buffer_new_and_alloc (size);
5451 gst_buffer_fill (buffer, 0, buf, size);
5452 stream->buffers = g_slist_append (stream->buffers, buffer);
5453 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
5456 GST_WARNING_OBJECT (qtdemux,
5457 "unknown theora cookie %" GST_FOURCC_FORMAT,
5458 GST_FOURCC_ARGS (type));
5467 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
5471 guint32 node_length = 0;
5472 const QtNodeType *type;
5475 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
5477 if (G_UNLIKELY (length < 8))
5478 goto not_enough_data;
5480 node_length = QT_UINT32 (buffer);
5481 fourcc = QT_FOURCC (buffer + 4);
5483 /* ignore empty nodes */
5484 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
5487 type = qtdemux_type_get (fourcc);
5489 end = buffer + length;
5491 GST_LOG_OBJECT (qtdemux,
5492 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
5493 GST_FOURCC_ARGS (fourcc), node_length, type->name);
5495 if (node_length > length)
5496 goto broken_atom_size;
5498 if (type->flags & QT_FLAG_CONTAINER) {
5499 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
5504 if (node_length < 20) {
5505 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
5508 GST_DEBUG_OBJECT (qtdemux,
5509 "parsing stsd (sample table, sample description) atom");
5510 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
5511 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
5521 /* also read alac (or whatever) in stead of mp4a in the following,
5522 * since a similar layout is used in other cases as well */
5523 if (fourcc == FOURCC_mp4a)
5528 /* There are two things we might encounter here: a true mp4a atom, and
5529 an mp4a entry in an stsd atom. The latter is what we're interested
5530 in, and it looks like an atom, but isn't really one. The true mp4a
5531 atom is short, so we detect it based on length here. */
5532 if (length < min_size) {
5533 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
5534 GST_FOURCC_ARGS (fourcc));
5538 /* 'version' here is the sound sample description version. Types 0 and
5539 1 are documented in the QTFF reference, but type 2 is not: it's
5540 described in Apple header files instead (struct SoundDescriptionV2
5542 version = QT_UINT16 (buffer + 16);
5544 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
5545 GST_FOURCC_ARGS (fourcc), version);
5547 /* parse any esds descriptors */
5559 GST_WARNING_OBJECT (qtdemux,
5560 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
5561 GST_FOURCC_ARGS (fourcc), version);
5566 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
5583 /* codec_data is contained inside these atoms, which all have
5584 * the same format. */
5586 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
5587 GST_FOURCC_ARGS (fourcc));
5588 version = QT_UINT32 (buffer + 16);
5589 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
5590 if (1 || version == 0x00000000) {
5591 buf = buffer + 0x32;
5593 /* FIXME Quicktime uses PASCAL string while
5594 * the iso format uses C strings. Check the file
5595 * type before attempting to parse the string here. */
5596 tlen = QT_UINT8 (buf);
5597 GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
5599 GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
5600 /* the string has a reserved space of 32 bytes so skip
5601 * the remaining 31 */
5603 buf += 4; /* and 4 bytes reserved */
5605 GST_MEMDUMP_OBJECT (qtdemux, "mp4v", buf, end - buf);
5607 qtdemux_parse_container (qtdemux, node, buf, end);
5613 GST_MEMDUMP_OBJECT (qtdemux, "H264", buffer, end - buffer);
5614 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
5619 GST_MEMDUMP_OBJECT (qtdemux, "avc1", buffer, end - buffer);
5620 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
5625 GST_MEMDUMP_OBJECT (qtdemux, "avc3", buffer, end - buffer);
5626 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
5631 GST_MEMDUMP_OBJECT (qtdemux, "H265", buffer, end - buffer);
5632 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
5637 GST_MEMDUMP_OBJECT (qtdemux, "hvc1", buffer, end - buffer);
5638 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
5643 GST_MEMDUMP_OBJECT (qtdemux, "hev1", buffer, end - buffer);
5644 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
5649 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
5654 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
5655 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
5660 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
5661 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
5662 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
5670 version = QT_UINT32 (buffer + 12);
5671 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
5678 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
5683 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
5688 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
5693 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
5697 if (!strcmp (type->name, "unknown"))
5698 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
5702 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
5703 GST_FOURCC_ARGS (fourcc));
5709 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5710 (_("This file is corrupt and cannot be played.")),
5711 ("Not enough data for an atom header, got only %u bytes", length));
5716 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5717 (_("This file is corrupt and cannot be played.")),
5718 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
5719 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
5726 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
5730 guint32 child_fourcc;
5732 for (child = g_node_first_child (node); child;
5733 child = g_node_next_sibling (child)) {
5734 buffer = (guint8 *) child->data;
5736 child_fourcc = QT_FOURCC (buffer + 4);
5738 if (G_UNLIKELY (child_fourcc == fourcc)) {
5746 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
5747 GstByteReader * parser)
5751 guint32 child_fourcc, child_len;
5753 for (child = g_node_first_child (node); child;
5754 child = g_node_next_sibling (child)) {
5755 buffer = (guint8 *) child->data;
5757 child_len = QT_UINT32 (buffer);
5758 child_fourcc = QT_FOURCC (buffer + 4);
5760 if (G_UNLIKELY (child_fourcc == fourcc)) {
5761 if (G_UNLIKELY (child_len < (4 + 4)))
5763 /* FIXME: must verify if atom length < parent atom length */
5764 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
5772 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
5773 GstByteReader * parser)
5777 guint32 child_fourcc, child_len;
5779 for (child = g_node_next_sibling (node); child;
5780 child = g_node_next_sibling (child)) {
5781 buffer = (guint8 *) child->data;
5783 child_fourcc = QT_FOURCC (buffer + 4);
5785 if (child_fourcc == fourcc) {
5787 child_len = QT_UINT32 (buffer);
5788 if (G_UNLIKELY (child_len < (4 + 4)))
5790 /* FIXME: must verify if atom length < parent atom length */
5791 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
5800 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
5802 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
5806 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
5808 /* FIXME: This can only reliably work if demuxers have a
5809 * separate streaming thread per srcpad. This should be
5810 * done in a demuxer base class, which integrates parts
5813 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
5818 query = gst_query_new_allocation (stream->caps, FALSE);
5820 if (!gst_pad_peer_query (stream->pad, query)) {
5821 /* not a problem, just debug a little */
5822 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
5825 if (stream->allocator)
5826 gst_object_unref (stream->allocator);
5828 if (gst_query_get_n_allocation_params (query) > 0) {
5829 /* try the allocator */
5830 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
5832 stream->use_allocator = TRUE;
5834 stream->allocator = NULL;
5835 gst_allocation_params_init (&stream->params);
5836 stream->use_allocator = FALSE;
5838 gst_query_unref (query);
5843 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
5845 if (stream->subtype == FOURCC_vide) {
5846 /* fps is calculated base on the duration of the first frames since
5847 * qt does not have a fixed framerate. */
5848 if ((stream->n_samples == 1) && (stream->min_duration == 0)) {
5853 /* we might need to scale the timescale to get precise framerate */
5854 const int required_scale = rint (log (10000) / 2.303); /* divide to get log10 */
5855 int current_scale = rint (log (stream->timescale) / 2.303);
5856 int factor = pow (10.0, MAX (0, required_scale - current_scale));
5858 stream->fps_n = stream->timescale * factor;
5860 if (stream->duration == 0 || stream->n_samples == 0)
5861 stream->fps_d = factor;
5864 gst_util_uint64_scale_int_round (stream->duration, factor,
5869 stream->caps = gst_caps_make_writable (stream->caps);
5871 gst_caps_set_simple (stream->caps,
5872 "width", G_TYPE_INT, stream->width,
5873 "height", G_TYPE_INT, stream->height,
5874 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
5876 /* calculate pixel-aspect-ratio using display width and height */
5877 GST_DEBUG_OBJECT (qtdemux,
5878 "video size %dx%d, target display size %dx%d", stream->width,
5879 stream->height, stream->display_width, stream->display_height);
5881 if (stream->display_width > 0 && stream->display_height > 0 &&
5882 stream->width > 0 && stream->height > 0) {
5885 /* calculate the pixel aspect ratio using the display and pixel w/h */
5886 n = stream->display_width * stream->height;
5887 d = stream->display_height * stream->width;
5890 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
5891 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
5892 GST_TYPE_FRACTION, n, d, NULL);
5895 /* qt file might have pasp atom */
5896 if (stream->par_w > 0 && stream->par_h > 0) {
5897 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
5898 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
5899 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
5902 } else if (stream->subtype == FOURCC_soun) {
5904 stream->caps = gst_caps_make_writable (stream->caps);
5905 if (stream->rate > 0)
5906 gst_caps_set_simple (stream->caps,
5907 "rate", G_TYPE_INT, (int) stream->rate, NULL);
5908 if (stream->n_channels > 0)
5909 gst_caps_set_simple (stream->caps,
5910 "channels", G_TYPE_INT, stream->n_channels, NULL);
5911 if (stream->n_channels > 2) {
5912 /* FIXME: Need to parse the 'chan' atom to get channel layouts
5913 * correctly; this is just the minimum we can do - assume
5914 * we don't actually have any channel positions. */
5915 gst_caps_set_simple (stream->caps,
5916 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
5922 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
5923 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
5924 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
5925 gst_pad_set_active (stream->pad, TRUE);
5927 gst_pad_use_fixed_caps (stream->pad);
5929 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
5930 if (stream->new_stream) {
5933 GstStreamFlags stream_flags;
5936 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
5939 if (gst_event_parse_group_id (event, &qtdemux->group_id))
5940 qtdemux->have_group_id = TRUE;
5942 qtdemux->have_group_id = FALSE;
5943 gst_event_unref (event);
5944 } else if (!qtdemux->have_group_id) {
5945 qtdemux->have_group_id = TRUE;
5946 qtdemux->group_id = gst_util_group_id_next ();
5949 stream->new_stream = FALSE;
5951 gst_pad_create_stream_id_printf (stream->pad,
5952 GST_ELEMENT_CAST (qtdemux), "%03u", stream->track_id);
5953 event = gst_event_new_stream_start (stream_id);
5954 if (qtdemux->have_group_id)
5955 gst_event_set_group_id (event, qtdemux->group_id);
5956 stream_flags = GST_STREAM_FLAG_NONE;
5957 if (stream->disabled)
5958 stream_flags |= GST_STREAM_FLAG_UNSELECT;
5960 stream_flags |= GST_STREAM_FLAG_SPARSE;
5961 gst_event_set_stream_flags (event, stream_flags);
5962 gst_pad_push_event (stream->pad, event);
5965 gst_pad_set_caps (stream->pad, stream->caps);
5966 stream->new_caps = FALSE;
5972 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
5973 QtDemuxStream * stream, GstTagList * list)
5975 /* consistent default for push based mode */
5976 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
5978 if (stream->subtype == FOURCC_vide) {
5979 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
5982 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
5985 gst_qtdemux_configure_stream (qtdemux, stream);
5986 qtdemux->n_video_streams++;
5987 } else if (stream->subtype == FOURCC_soun) {
5988 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
5991 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
5993 gst_qtdemux_configure_stream (qtdemux, stream);
5994 qtdemux->n_audio_streams++;
5995 } else if (stream->subtype == FOURCC_strm) {
5996 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
5997 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
5998 || stream->subtype == FOURCC_sbtl) {
5999 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
6002 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
6004 gst_qtdemux_configure_stream (qtdemux, stream);
6005 qtdemux->n_sub_streams++;
6006 } else if (stream->caps) {
6007 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
6010 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
6012 gst_qtdemux_configure_stream (qtdemux, stream);
6013 qtdemux->n_video_streams++;
6015 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
6020 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
6021 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
6022 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
6024 if (stream->pending_tags)
6025 gst_tag_list_unref (stream->pending_tags);
6026 stream->pending_tags = list;
6027 /* global tags go on each pad anyway */
6028 stream->send_global_tags = TRUE;
6034 /* find next atom with @fourcc starting at @offset */
6035 static GstFlowReturn
6036 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
6037 guint64 * length, guint32 fourcc)
6043 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
6044 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
6050 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
6051 if (G_UNLIKELY (ret != GST_FLOW_OK))
6053 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
6056 gst_buffer_unref (buf);
6059 gst_buffer_map (buf, &map, GST_MAP_READ);
6060 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
6061 gst_buffer_unmap (buf, &map);
6062 gst_buffer_unref (buf);
6064 if (G_UNLIKELY (*length == 0)) {
6065 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
6066 ret = GST_FLOW_ERROR;
6070 if (lfourcc == fourcc) {
6071 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
6075 GST_LOG_OBJECT (qtdemux,
6076 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
6077 GST_FOURCC_ARGS (fourcc), *offset);
6086 /* might simply have had last one */
6087 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
6092 /* should only do something in pull mode */
6093 /* call with OBJECT lock */
6094 static GstFlowReturn
6095 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
6097 guint64 length, offset;
6098 GstBuffer *buf = NULL;
6099 GstFlowReturn ret = GST_FLOW_OK;
6100 GstFlowReturn res = GST_FLOW_OK;
6103 offset = qtdemux->moof_offset;
6104 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
6107 GST_DEBUG_OBJECT (qtdemux, "no next moof");
6108 return GST_FLOW_EOS;
6111 /* best not do pull etc with lock held */
6112 GST_OBJECT_UNLOCK (qtdemux);
6114 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
6115 if (ret != GST_FLOW_OK)
6118 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
6119 if (G_UNLIKELY (ret != GST_FLOW_OK))
6121 gst_buffer_map (buf, &map, GST_MAP_READ);
6122 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
6123 gst_buffer_unmap (buf, &map);
6124 gst_buffer_unref (buf);
6129 gst_buffer_unmap (buf, &map);
6130 gst_buffer_unref (buf);
6134 /* look for next moof */
6135 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
6136 if (G_UNLIKELY (ret != GST_FLOW_OK))
6140 GST_OBJECT_LOCK (qtdemux);
6142 qtdemux->moof_offset = offset;
6148 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
6150 res = GST_FLOW_ERROR;
6155 /* maybe upstream temporarily flushing */
6156 if (ret != GST_FLOW_FLUSHING) {
6157 GST_DEBUG_OBJECT (qtdemux, "no next moof");
6160 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
6161 /* resume at current position next time */
6168 /* initialise bytereaders for stbl sub-atoms */
6170 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
6172 stream->stbl_index = -1; /* no samples have yet been parsed */
6173 stream->sample_index = -1;
6175 /* time-to-sample atom */
6176 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
6179 /* copy atom data into a new buffer for later use */
6180 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
6182 /* skip version + flags */
6183 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
6184 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
6186 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
6188 /* make sure there's enough data */
6189 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
6190 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
6191 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
6192 stream->n_sample_times);
6193 if (!stream->n_sample_times)
6197 /* sync sample atom */
6198 stream->stps_present = FALSE;
6199 if ((stream->stss_present =
6200 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
6201 &stream->stss) ? TRUE : FALSE) == TRUE) {
6202 /* copy atom data into a new buffer for later use */
6203 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
6205 /* skip version + flags */
6206 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
6207 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
6210 if (stream->n_sample_syncs) {
6211 /* make sure there's enough data */
6212 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
6216 /* partial sync sample atom */
6217 if ((stream->stps_present =
6218 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
6219 &stream->stps) ? TRUE : FALSE) == TRUE) {
6220 /* copy atom data into a new buffer for later use */
6221 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
6223 /* skip version + flags */
6224 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
6225 !gst_byte_reader_get_uint32_be (&stream->stps,
6226 &stream->n_sample_partial_syncs))
6229 /* if there are no entries, the stss table contains the real
6231 if (stream->n_sample_partial_syncs) {
6232 /* make sure there's enough data */
6233 if (!qt_atom_parser_has_chunks (&stream->stps,
6234 stream->n_sample_partial_syncs, 4))
6241 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
6244 /* copy atom data into a new buffer for later use */
6245 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
6247 /* skip version + flags */
6248 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
6249 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
6252 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
6255 if (!stream->n_samples)
6258 /* sample-to-chunk atom */
6259 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
6262 /* copy atom data into a new buffer for later use */
6263 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
6265 /* skip version + flags */
6266 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
6267 !gst_byte_reader_get_uint32_be (&stream->stsc,
6268 &stream->n_samples_per_chunk))
6271 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
6272 stream->n_samples_per_chunk);
6274 /* make sure there's enough data */
6275 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
6281 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
6282 stream->co_size = sizeof (guint32);
6283 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
6285 stream->co_size = sizeof (guint64);
6289 /* copy atom data into a new buffer for later use */
6290 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
6292 /* skip version + flags */
6293 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
6296 /* chunks_are_samples == TRUE means treat chunks as samples */
6297 stream->chunks_are_samples = stream->sample_size && !stream->sampled;
6298 if (stream->chunks_are_samples) {
6299 /* treat chunks as samples */
6300 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
6303 /* skip number of entries */
6304 if (!gst_byte_reader_skip (&stream->stco, 4))
6307 /* make sure there are enough data in the stsz atom */
6308 if (!stream->sample_size) {
6309 /* different sizes for each sample */
6310 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
6315 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
6316 stream->n_samples, (guint) sizeof (QtDemuxSample),
6317 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
6319 if (stream->n_samples >=
6320 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
6321 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
6322 "be larger than %uMB (broken file?)", stream->n_samples,
6323 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
6327 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
6328 if (!stream->samples) {
6329 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
6335 /* composition time-to-sample */
6336 if ((stream->ctts_present =
6337 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
6338 &stream->ctts) ? TRUE : FALSE) == TRUE) {
6339 /* copy atom data into a new buffer for later use */
6340 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
6342 /* skip version + flags */
6343 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
6344 || !gst_byte_reader_get_uint32_be (&stream->ctts,
6345 &stream->n_composition_times))
6348 /* make sure there's enough data */
6349 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
6358 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
6359 (_("This file is corrupt and cannot be played.")), (NULL));
6364 gst_qtdemux_stbl_free (stream);
6365 if (!qtdemux->fragmented) {
6366 /* not quite good */
6367 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
6370 /* may pick up samples elsewhere */
6376 /* collect samples from the next sample to be parsed up to sample @n for @stream
6377 * by reading the info from @stbl
6379 * This code can be executed from both the streaming thread and the seeking
6380 * thread so it takes the object lock to protect itself
6383 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
6386 QtDemuxSample *samples, *first, *cur, *last;
6387 guint32 n_samples_per_chunk;
6390 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
6391 GST_FOURCC_FORMAT ", pad %s", GST_FOURCC_ARGS (stream->fourcc),
6392 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
6394 n_samples = stream->n_samples;
6397 goto out_of_samples;
6399 GST_OBJECT_LOCK (qtdemux);
6400 if (n <= stream->stbl_index)
6401 goto already_parsed;
6403 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
6405 if (!stream->stsz.data) {
6406 /* so we already parsed and passed all the moov samples;
6407 * onto fragmented ones */
6408 g_assert (qtdemux->fragmented);
6412 /* pointer to the sample table */
6413 samples = stream->samples;
6415 /* starts from -1, moves to the next sample index to parse */
6416 stream->stbl_index++;
6418 /* keep track of the first and last sample to fill */
6419 first = &samples[stream->stbl_index];
6422 if (!stream->chunks_are_samples) {
6423 /* set the sample sizes */
6424 if (stream->sample_size == 0) {
6425 /* different sizes for each sample */
6426 for (cur = first; cur <= last; cur++) {
6427 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
6428 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
6429 (guint) (cur - samples), cur->size);
6432 /* samples have the same size */
6433 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
6434 for (cur = first; cur <= last; cur++)
6435 cur->size = stream->sample_size;
6439 n_samples_per_chunk = stream->n_samples_per_chunk;
6442 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
6445 if (stream->stsc_chunk_index >= stream->last_chunk
6446 || stream->stsc_chunk_index < stream->first_chunk) {
6447 stream->first_chunk =
6448 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
6449 stream->samples_per_chunk =
6450 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
6451 gst_byte_reader_skip_unchecked (&stream->stsc, 4);
6453 /* chunk numbers are counted from 1 it seems */
6454 if (G_UNLIKELY (stream->first_chunk == 0))
6457 --stream->first_chunk;
6459 /* the last chunk of each entry is calculated by taking the first chunk
6460 * of the next entry; except if there is no next, where we fake it with
6462 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
6463 stream->last_chunk = G_MAXUINT32;
6465 stream->last_chunk =
6466 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
6467 if (G_UNLIKELY (stream->last_chunk == 0))
6470 --stream->last_chunk;
6473 GST_LOG_OBJECT (qtdemux,
6474 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
6475 stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
6477 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
6480 if (stream->last_chunk != G_MAXUINT32) {
6481 if (!qt_atom_parser_peek_sub (&stream->stco,
6482 stream->first_chunk * stream->co_size,
6483 (stream->last_chunk - stream->first_chunk) * stream->co_size,
6488 stream->co_chunk = stream->stco;
6489 if (!gst_byte_reader_skip (&stream->co_chunk,
6490 stream->first_chunk * stream->co_size))
6494 stream->stsc_chunk_index = stream->first_chunk;
6497 last_chunk = stream->last_chunk;
6499 if (stream->chunks_are_samples) {
6500 cur = &samples[stream->stsc_chunk_index];
6502 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
6505 stream->stsc_chunk_index = j;
6510 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
6513 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
6514 "%" G_GUINT64_FORMAT, j, cur->offset);
6516 if (stream->samples_per_frame * stream->bytes_per_frame) {
6518 (stream->samples_per_chunk * stream->n_channels) /
6519 stream->samples_per_frame * stream->bytes_per_frame;
6521 cur->size = stream->samples_per_chunk;
6524 GST_DEBUG_OBJECT (qtdemux,
6525 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
6526 j, GST_TIME_ARGS (gst_util_uint64_scale (stream->stco_sample_index,
6527 GST_SECOND, stream->timescale)), cur->size);
6529 cur->timestamp = stream->stco_sample_index;
6530 cur->duration = stream->samples_per_chunk;
6531 cur->keyframe = TRUE;
6534 stream->stco_sample_index += stream->samples_per_chunk;
6536 stream->stsc_chunk_index = j;
6538 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
6539 guint32 samples_per_chunk;
6540 guint64 chunk_offset;
6542 if (!stream->stsc_sample_index
6543 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
6544 &stream->chunk_offset))
6547 samples_per_chunk = stream->samples_per_chunk;
6548 chunk_offset = stream->chunk_offset;
6550 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
6551 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
6552 G_GUINT64_FORMAT " and size %d",
6553 (guint) (cur - samples), stream->chunk_offset, cur->size);
6555 cur->offset = chunk_offset;
6556 chunk_offset += cur->size;
6559 if (G_UNLIKELY (cur > last)) {
6561 stream->stsc_sample_index = k + 1;
6562 stream->chunk_offset = chunk_offset;
6563 stream->stsc_chunk_index = j;
6567 stream->stsc_sample_index = 0;
6569 stream->stsc_chunk_index = j;
6571 stream->stsc_index++;
6574 if (stream->chunks_are_samples)
6578 guint32 n_sample_times;
6580 n_sample_times = stream->n_sample_times;
6583 for (i = stream->stts_index; i < n_sample_times; i++) {
6584 guint32 stts_samples;
6585 gint32 stts_duration;
6588 if (stream->stts_sample_index >= stream->stts_samples
6589 || !stream->stts_sample_index) {
6591 stream->stts_samples =
6592 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
6593 stream->stts_duration =
6594 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
6596 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
6597 i, stream->stts_samples, stream->stts_duration);
6599 stream->stts_sample_index = 0;
6602 stts_samples = stream->stts_samples;
6603 stts_duration = stream->stts_duration;
6604 stts_time = stream->stts_time;
6606 for (j = stream->stts_sample_index; j < stts_samples; j++) {
6607 GST_DEBUG_OBJECT (qtdemux,
6608 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
6609 (guint) (cur - samples), j,
6610 GST_TIME_ARGS (gst_util_uint64_scale (stts_time, GST_SECOND,
6611 stream->timescale)));
6613 cur->timestamp = stts_time;
6614 cur->duration = stts_duration;
6616 /* avoid 32-bit wrap-around,
6617 * but still mind possible 'negative' duration */
6618 stts_time += (gint64) stts_duration;
6621 if (G_UNLIKELY (cur > last)) {
6623 stream->stts_time = stts_time;
6624 stream->stts_sample_index = j + 1;
6628 stream->stts_sample_index = 0;
6629 stream->stts_time = stts_time;
6630 stream->stts_index++;
6632 /* fill up empty timestamps with the last timestamp, this can happen when
6633 * the last samples do not decode and so we don't have timestamps for them.
6634 * We however look at the last timestamp to estimate the track length so we
6635 * need something in here. */
6636 for (; cur < last; cur++) {
6637 GST_DEBUG_OBJECT (qtdemux,
6638 "fill sample %d: timestamp %" GST_TIME_FORMAT,
6639 (guint) (cur - samples),
6640 GST_TIME_ARGS (gst_util_uint64_scale (stream->stts_time, GST_SECOND,
6641 stream->timescale)));
6642 cur->timestamp = stream->stts_time;
6648 /* sample sync, can be NULL */
6649 if (stream->stss_present == TRUE) {
6650 guint32 n_sample_syncs;
6652 n_sample_syncs = stream->n_sample_syncs;
6654 if (!n_sample_syncs) {
6655 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
6656 stream->all_keyframe = TRUE;
6658 for (i = stream->stss_index; i < n_sample_syncs; i++) {
6659 /* note that the first sample is index 1, not 0 */
6662 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
6664 if (G_LIKELY (index > 0 && index <= n_samples)) {
6666 samples[index].keyframe = TRUE;
6667 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
6668 /* and exit if we have enough samples */
6669 if (G_UNLIKELY (index >= n)) {
6676 stream->stss_index = i;
6679 /* stps marks partial sync frames like open GOP I-Frames */
6680 if (stream->stps_present == TRUE) {
6681 guint32 n_sample_partial_syncs;
6683 n_sample_partial_syncs = stream->n_sample_partial_syncs;
6685 /* if there are no entries, the stss table contains the real
6687 if (n_sample_partial_syncs) {
6688 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
6689 /* note that the first sample is index 1, not 0 */
6692 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
6694 if (G_LIKELY (index > 0 && index <= n_samples)) {
6696 samples[index].keyframe = TRUE;
6697 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
6698 /* and exit if we have enough samples */
6699 if (G_UNLIKELY (index >= n)) {
6706 stream->stps_index = i;
6710 /* no stss, all samples are keyframes */
6711 stream->all_keyframe = TRUE;
6712 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
6717 /* composition time to sample */
6718 if (stream->ctts_present == TRUE) {
6719 guint32 n_composition_times;
6721 gint32 ctts_soffset;
6723 /* Fill in the pts_offsets */
6725 n_composition_times = stream->n_composition_times;
6727 for (i = stream->ctts_index; i < n_composition_times; i++) {
6728 if (stream->ctts_sample_index >= stream->ctts_count
6729 || !stream->ctts_sample_index) {
6730 stream->ctts_count =
6731 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
6732 stream->ctts_soffset =
6733 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
6734 stream->ctts_sample_index = 0;
6737 ctts_count = stream->ctts_count;
6738 ctts_soffset = stream->ctts_soffset;
6740 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
6741 cur->pts_offset = ctts_soffset;
6744 if (G_UNLIKELY (cur > last)) {
6746 stream->ctts_sample_index = j + 1;
6750 stream->ctts_sample_index = 0;
6751 stream->ctts_index++;
6755 stream->stbl_index = n;
6756 /* if index has been completely parsed, free data that is no-longer needed */
6757 if (n + 1 == stream->n_samples) {
6758 gst_qtdemux_stbl_free (stream);
6759 GST_DEBUG_OBJECT (qtdemux,
6760 "parsed all available samples; checking for more");
6761 while (n + 1 == stream->n_samples)
6762 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
6765 GST_OBJECT_UNLOCK (qtdemux);
6772 GST_LOG_OBJECT (qtdemux,
6773 "Tried to parse up to sample %u but this sample has already been parsed",
6775 /* if fragmented, there may be more */
6776 if (qtdemux->fragmented && n == stream->stbl_index)
6778 GST_OBJECT_UNLOCK (qtdemux);
6784 GST_LOG_OBJECT (qtdemux,
6785 "Tried to parse up to sample %u but there are only %u samples", n + 1,
6787 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
6788 (_("This file is corrupt and cannot be played.")), (NULL));
6793 GST_OBJECT_UNLOCK (qtdemux);
6794 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
6795 (_("This file is corrupt and cannot be played.")), (NULL));
6800 /* collect all segment info for @stream.
6803 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
6808 /* parse and prepare segment info from the edit list */
6809 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
6810 stream->n_segments = 0;
6811 stream->segments = NULL;
6812 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
6816 guint64 time, stime;
6819 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
6820 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
6823 buffer = elst->data;
6825 n_segments = QT_UINT32 (buffer + 12);
6827 /* we might allocate a bit too much, at least allocate 1 segment */
6828 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
6830 /* segments always start from 0 */
6834 for (i = 0; i < n_segments; i++) {
6837 QtDemuxSegment *segment;
6840 media_time = QT_UINT32 (buffer + 20 + i * 12);
6841 duration = QT_UINT32 (buffer + 16 + i * 12);
6843 segment = &stream->segments[count++];
6845 /* time and duration expressed in global timescale */
6846 segment->time = stime;
6847 /* add non scaled values so we don't cause roundoff errors */
6849 stime = gst_util_uint64_scale (time, GST_SECOND, qtdemux->timescale);
6850 segment->stop_time = stime;
6851 segment->duration = stime - segment->time;
6852 /* media_time expressed in stream timescale */
6853 if (media_time != G_MAXUINT32) {
6854 segment->media_start =
6855 gst_util_uint64_scale (media_time, GST_SECOND, stream->timescale);
6856 segment->media_stop = segment->media_start + segment->duration;
6858 segment->media_start = GST_CLOCK_TIME_NONE;
6859 segment->media_stop = GST_CLOCK_TIME_NONE;
6861 rate_int = GST_READ_UINT32_BE (buffer + 24 + i * 12);
6863 if (rate_int <= 1) {
6864 /* 0 is not allowed, some programs write 1 instead of the floating point
6866 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
6870 segment->rate = rate_int / 65536.0;
6873 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
6874 ", duration %" GST_TIME_FORMAT ", media_time %" GST_TIME_FORMAT
6875 ", rate %g, (%d)", i, GST_TIME_ARGS (segment->time),
6876 GST_TIME_ARGS (segment->duration),
6877 GST_TIME_ARGS (segment->media_start), segment->rate, rate_int);
6879 GST_DEBUG_OBJECT (qtdemux, "found %d segments", count);
6880 stream->n_segments = count;
6884 /* push based does not handle segments, so act accordingly here,
6885 * and warn if applicable */
6886 if (!qtdemux->pullbased) {
6887 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
6888 /* remove and use default one below, we stream like it anyway */
6889 g_free (stream->segments);
6890 stream->segments = NULL;
6891 stream->n_segments = 0;
6894 /* no segments, create one to play the complete trak */
6895 if (stream->n_segments == 0) {
6896 GstClockTime stream_duration =
6897 gst_util_uint64_scale (stream->duration, GST_SECOND, stream->timescale);
6899 if (stream->segments == NULL)
6900 stream->segments = g_new (QtDemuxSegment, 1);
6902 /* represent unknown our way */
6903 if (stream_duration == 0)
6904 stream_duration = -1;
6906 stream->segments[0].time = 0;
6907 stream->segments[0].stop_time = stream_duration;
6908 stream->segments[0].duration = stream_duration;
6909 stream->segments[0].media_start = 0;
6910 stream->segments[0].media_stop = stream_duration;
6911 stream->segments[0].rate = 1.0;
6913 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
6914 GST_TIME_ARGS (stream_duration));
6915 stream->n_segments = 1;
6917 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
6923 * Parses the stsd atom of a svq3 trak looking for
6924 * the SMI and gama atoms.
6927 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
6928 guint8 ** gamma, GstBuffer ** seqh)
6930 guint8 *_gamma = NULL;
6931 GstBuffer *_seqh = NULL;
6932 guint8 *stsd_data = stsd->data;
6933 guint32 length = QT_UINT32 (stsd_data);
6937 GST_WARNING_OBJECT (qtdemux, "stsd too short");
6943 version = QT_UINT16 (stsd_data);
6948 while (length > 8) {
6949 guint32 fourcc, size;
6951 size = QT_UINT32 (stsd_data);
6952 fourcc = QT_FOURCC (stsd_data + 4);
6953 data = stsd_data + 8;
6960 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
6961 " for gama atom, expected 12", size);
6966 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
6968 if (_seqh != NULL) {
6969 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
6970 " found, ignoring");
6972 seqh_size = QT_UINT32 (data + 4);
6973 if (seqh_size > 0) {
6974 _seqh = gst_buffer_new_and_alloc (seqh_size);
6975 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
6982 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
6983 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
6987 if (size <= length) {
6993 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
6996 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
6997 G_GUINT16_FORMAT, version);
7008 gst_buffer_unref (_seqh);
7013 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
7020 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
7021 * atom that might contain a 'data' atom with the rtsp uri.
7022 * This case was reported in bug #597497, some info about
7023 * the hndl atom can be found in TN1195
7025 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
7026 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
7029 guint32 dref_num_entries = 0;
7030 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
7031 gst_byte_reader_skip (&dref, 4) &&
7032 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
7035 /* search dref entries for hndl atom */
7036 for (i = 0; i < dref_num_entries; i++) {
7037 guint32 size = 0, type;
7038 guint8 string_len = 0;
7039 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
7040 qt_atom_parser_get_fourcc (&dref, &type)) {
7041 if (type == FOURCC_hndl) {
7042 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
7044 /* skip data reference handle bytes and the
7045 * following pascal string and some extra 4
7046 * bytes I have no idea what are */
7047 if (!gst_byte_reader_skip (&dref, 4) ||
7048 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
7049 !gst_byte_reader_skip (&dref, string_len + 4)) {
7050 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
7054 /* iterate over the atoms to find the data atom */
7055 while (gst_byte_reader_get_remaining (&dref) >= 8) {
7059 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
7060 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
7061 if (atom_type == FOURCC_data) {
7062 const guint8 *uri_aux = NULL;
7064 /* found the data atom that might contain the rtsp uri */
7065 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
7066 "hndl atom, interpreting it as an URI");
7067 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
7069 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
7070 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
7072 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
7073 "didn't contain a rtsp address");
7075 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
7080 /* skipping to the next entry */
7081 if (!gst_byte_reader_skip (&dref, atom_size - 8))
7084 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
7091 /* skip to the next entry */
7092 if (!gst_byte_reader_skip (&dref, size - 8))
7095 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
7098 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
7105 less_than (gconstpointer a, gconstpointer b)
7107 const guint32 *av = a, *bv = b;
7112 #define AMR_NB_ALL_MODES 0x81ff
7113 #define AMR_WB_ALL_MODES 0x83ff
7115 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
7117 /* The 'damr' atom is of the form:
7119 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
7120 * 32 b 8 b 16 b 8 b 8 b
7122 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
7123 * represents the highest mode used in the stream (and thus the maximum
7124 * bitrate), with a couple of special cases as seen below.
7127 /* Map of frame type ID -> bitrate */
7128 static const guint nb_bitrates[] = {
7129 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
7131 static const guint wb_bitrates[] = {
7132 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
7138 gst_buffer_map (buf, &map, GST_MAP_READ);
7140 if (map.size != 0x11) {
7141 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
7145 if (QT_FOURCC (map.data + 4) != GST_MAKE_FOURCC ('d', 'a', 'm', 'r')) {
7146 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
7147 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
7151 mode_set = QT_UINT16 (map.data + 13);
7153 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
7154 max_mode = 7 + (wb ? 1 : 0);
7156 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
7157 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
7159 if (max_mode == -1) {
7160 GST_DEBUG ("No mode indication was found (mode set) = %x",
7165 gst_buffer_unmap (buf, &map);
7166 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
7169 gst_buffer_unmap (buf, &map);
7174 * With each track we associate a new QtDemuxStream that contains all the info
7176 * traks that do not decode to something (like strm traks) will not have a pad.
7179 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
7196 QtDemuxStream *stream = NULL;
7197 gboolean new_stream = FALSE;
7198 GstTagList *list = NULL;
7199 gchar *codec = NULL;
7200 const guint8 *stsd_data;
7201 guint16 lang_code; /* quicktime lang code or packed iso code */
7203 guint32 tkhd_flags = 0;
7204 guint8 tkhd_version = 0;
7206 guint value_size, stsd_len, len;
7209 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
7211 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
7212 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
7213 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
7216 /* pick between 64 or 32 bits */
7217 value_size = tkhd_version == 1 ? 8 : 4;
7218 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
7219 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
7222 if (!qtdemux->got_moov) {
7223 if (qtdemux_find_stream (qtdemux, track_id))
7224 goto existing_stream;
7225 stream = _create_stream ();
7226 stream->track_id = track_id;
7229 stream = qtdemux_find_stream (qtdemux, track_id);
7231 GST_WARNING_OBJECT (qtdemux, "Stream not found, going to ignore it");
7236 if ((tkhd_flags & 1) == 0)
7237 stream->disabled = TRUE;
7239 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
7240 tkhd_version, tkhd_flags, stream->track_id);
7242 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
7245 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
7246 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
7247 if (qtdemux->major_brand != FOURCC_mjp2 ||
7248 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
7252 len = QT_UINT32 ((guint8 *) mdhd->data);
7253 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
7254 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
7255 if (version == 0x01000000) {
7258 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
7259 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
7260 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
7264 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
7265 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
7266 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
7269 if (lang_code < 0x800) {
7270 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
7272 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
7273 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
7274 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
7275 stream->lang_id[3] = 0;
7278 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
7280 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
7282 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
7283 lang_code, stream->lang_id);
7285 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
7288 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
7289 /* chapters track reference */
7290 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
7292 gsize length = GST_READ_UINT32_BE (chap->data);
7293 if (qtdemux->chapters_track_id)
7294 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
7297 qtdemux->chapters_track_id =
7298 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
7303 /* fragmented files may have bogus duration in moov */
7304 if (!qtdemux->fragmented &&
7305 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
7306 guint64 tdur1, tdur2;
7308 /* don't overflow */
7309 tdur1 = stream->timescale * (guint64) qtdemux->duration;
7310 tdur2 = qtdemux->timescale * (guint64) stream->duration;
7313 * some of those trailers, nowadays, have prologue images that are
7314 * themselves vide tracks as well. I haven't really found a way to
7315 * identify those yet, except for just looking at their duration. */
7316 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
7317 GST_WARNING_OBJECT (qtdemux,
7318 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
7319 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
7320 "found, assuming preview image or something; skipping track",
7321 stream->duration, stream->timescale, qtdemux->duration,
7322 qtdemux->timescale);
7328 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
7331 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
7332 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
7334 len = QT_UINT32 ((guint8 *) hdlr->data);
7336 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
7337 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
7338 GST_FOURCC_ARGS (stream->subtype));
7340 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
7343 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
7347 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
7349 stsd_data = (const guint8 *) stsd->data;
7351 /* stsd should at least have one entry */
7352 stsd_len = QT_UINT32 (stsd_data);
7353 if (stsd_len < 24) {
7354 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
7355 if (stream->subtype == FOURCC_vivo) {
7363 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
7365 /* and that entry should fit within stsd */
7366 len = QT_UINT32 (stsd_data + 16);
7367 if (len > stsd_len + 16)
7370 stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
7371 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
7372 GST_FOURCC_ARGS (stream->fourcc));
7373 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
7375 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi) ||
7376 ((fourcc & 0x00FFFFFF) == GST_MAKE_FOURCC ('e', 'n', 'c', 0)))
7377 goto error_encrypted;
7379 if (stream->subtype == FOURCC_vide) {
7380 guint32 w = 0, h = 0;
7382 gint depth, palette_size, palette_count;
7383 guint32 *palette_data = NULL;
7385 stream->sampled = TRUE;
7387 /* version 1 uses some 64-bit ints */
7388 if (!gst_byte_reader_skip (&tkhd, 56 + value_size)
7389 || !gst_byte_reader_get_uint32_be (&tkhd, &w)
7390 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
7393 stream->display_width = w >> 16;
7394 stream->display_height = h >> 16;
7400 stream->width = QT_UINT16 (stsd_data + offset + 32);
7401 stream->height = QT_UINT16 (stsd_data + offset + 34);
7402 stream->fps_n = 0; /* this is filled in later */
7403 stream->fps_d = 0; /* this is filled in later */
7404 stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
7405 stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
7407 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
7408 stream->width, stream->height, stream->bits_per_sample,
7409 stream->color_table_id);
7411 depth = stream->bits_per_sample;
7413 /* more than 32 bits means grayscale */
7414 gray = (depth > 32);
7415 /* low 32 bits specify the depth */
7418 /* different number of palette entries is determined by depth. */
7420 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
7421 palette_count = (1 << depth);
7422 palette_size = palette_count * 4;
7424 if (stream->color_table_id) {
7425 switch (palette_count) {
7429 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
7432 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
7436 palette_data = g_memdup (ff_qt_grayscale_palette_16, palette_size);
7438 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
7442 palette_data = g_memdup (ff_qt_grayscale_palette_256, palette_size);
7444 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
7447 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
7448 (_("The video in this file might not play correctly.")),
7449 ("unsupported palette depth %d", depth));
7453 gint i, j, start, end;
7459 start = QT_UINT32 (stsd_data + offset + 86);
7460 palette_count = QT_UINT16 (stsd_data + offset + 90);
7461 end = QT_UINT16 (stsd_data + offset + 92);
7463 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
7464 start, end, palette_count);
7471 if (len < 94 + (end - start) * 8)
7474 /* palette is always the same size */
7475 palette_data = g_malloc0 (256 * 4);
7476 palette_size = 256 * 4;
7478 for (j = 0, i = start; i <= end; j++, i++) {
7481 a = QT_UINT16 (stsd_data + offset + 94 + (j * 8));
7482 r = QT_UINT16 (stsd_data + offset + 96 + (j * 8));
7483 g = QT_UINT16 (stsd_data + offset + 98 + (j * 8));
7484 b = QT_UINT16 (stsd_data + offset + 100 + (j * 8));
7486 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
7487 (g & 0xff00) | (b >> 8);
7492 qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
7493 if (G_UNLIKELY (!stream->caps)) {
7494 g_free (palette_data);
7495 goto unknown_stream;
7499 list = gst_tag_list_new_empty ();
7500 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7501 GST_TAG_VIDEO_CODEC, codec, NULL);
7510 if (stream->rgb8_palette)
7511 gst_memory_unref (stream->rgb8_palette);
7512 stream->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
7513 palette_data, palette_size, 0, palette_size, palette_data, g_free);
7515 s = gst_caps_get_structure (stream->caps, 0);
7517 /* non-raw video has a palette_data property. raw video has the palette as
7518 * an extra plane that we append to the output buffers before we push
7520 if (!gst_structure_has_name (s, "video/x-raw")) {
7523 palette = gst_buffer_new ();
7524 gst_buffer_append_memory (palette, stream->rgb8_palette);
7525 stream->rgb8_palette = NULL;
7527 gst_caps_set_simple (stream->caps, "palette_data",
7528 GST_TYPE_BUFFER, palette, NULL);
7529 gst_buffer_unref (palette);
7531 } else if (palette_count != 0) {
7532 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
7533 (NULL), ("Unsupported palette depth %d", depth));
7536 GST_LOG_OBJECT (qtdemux, "frame count: %u",
7537 QT_UINT16 (stsd_data + offset + 48));
7541 /* pick 'the' stsd child */
7542 mp4v = qtdemux_tree_get_child_by_type (stsd, fourcc);
7544 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
7545 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
7549 const guint8 *pasp_data = (const guint8 *) pasp->data;
7551 stream->par_w = QT_UINT32 (pasp_data + 8);
7552 stream->par_h = QT_UINT32 (pasp_data + 12);
7559 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
7566 gint len = QT_UINT32 (stsd_data) - 0x66;
7567 const guint8 *avc_data = stsd_data + 0x66;
7570 while (len >= 0x8) {
7573 if (QT_UINT32 (avc_data) <= len)
7574 size = QT_UINT32 (avc_data) - 0x8;
7579 /* No real data, so break out */
7582 switch (QT_FOURCC (avc_data + 0x4)) {
7585 /* parse, if found */
7588 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
7590 /* First 4 bytes are the length of the atom, the next 4 bytes
7591 * are the fourcc, the next 1 byte is the version, and the
7592 * subsequent bytes are profile_tier_level structure like data. */
7593 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
7594 avc_data + 8 + 1, size - 1);
7595 buf = gst_buffer_new_and_alloc (size);
7596 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
7597 gst_caps_set_simple (stream->caps,
7598 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7599 gst_buffer_unref (buf);
7607 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
7609 /* First 4 bytes are the length of the atom, the next 4 bytes
7610 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
7611 * next 1 byte is the version, and the
7612 * subsequent bytes are sequence parameter set like data. */
7614 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
7616 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
7617 avc_data + 8 + 40 + 1, size - 1);
7619 buf = gst_buffer_new_and_alloc (size);
7620 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
7621 gst_caps_set_simple (stream->caps,
7622 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7623 gst_buffer_unref (buf);
7629 guint avg_bitrate, max_bitrate;
7631 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
7635 max_bitrate = QT_UINT32 (avc_data + 0xc);
7636 avg_bitrate = QT_UINT32 (avc_data + 0x10);
7638 if (!max_bitrate && !avg_bitrate)
7641 /* Some muxers seem to swap the average and maximum bitrates
7642 * (I'm looking at you, YouTube), so we swap for sanity. */
7643 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
7644 guint temp = avg_bitrate;
7646 avg_bitrate = max_bitrate;
7651 list = gst_tag_list_new_empty ();
7653 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
7654 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7655 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
7657 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
7658 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7659 GST_TAG_BITRATE, avg_bitrate, NULL);
7670 avc_data += size + 8;
7679 gint len = QT_UINT32 (stsd_data) - 0x66;
7680 const guint8 *hevc_data = stsd_data + 0x66;
7683 while (len >= 0x8) {
7686 if (QT_UINT32 (hevc_data) <= len)
7687 size = QT_UINT32 (hevc_data) - 0x8;
7692 /* No real data, so break out */
7695 switch (QT_FOURCC (hevc_data + 0x4)) {
7698 /* parse, if found */
7701 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
7703 /* First 4 bytes are the length of the atom, the next 4 bytes
7704 * are the fourcc, the next 1 byte is the version, and the
7705 * subsequent bytes are sequence parameter set like data. */
7706 gst_codec_utils_h265_caps_set_level_tier_and_profile
7707 (stream->caps, hevc_data + 8 + 1, size - 1);
7709 buf = gst_buffer_new_and_alloc (size);
7710 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
7711 gst_caps_set_simple (stream->caps,
7712 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7713 gst_buffer_unref (buf);
7720 hevc_data += size + 8;
7731 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
7732 GST_FOURCC_ARGS (fourcc));
7734 /* codec data might be in glbl extension atom */
7736 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
7742 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
7744 len = QT_UINT32 (data);
7747 buf = gst_buffer_new_and_alloc (len);
7748 gst_buffer_fill (buf, 0, data + 8, len);
7749 gst_caps_set_simple (stream->caps,
7750 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7751 gst_buffer_unref (buf);
7758 /* see annex I of the jpeg2000 spec */
7759 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
7761 const gchar *colorspace = NULL;
7763 guint32 ncomp_map = 0;
7764 gint32 *comp_map = NULL;
7765 guint32 nchan_def = 0;
7766 gint32 *chan_def = NULL;
7768 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
7769 /* some required atoms */
7770 mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
7773 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
7777 /* number of components; redundant with info in codestream, but useful
7779 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
7780 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
7782 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
7784 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
7787 GST_DEBUG_OBJECT (qtdemux, "found colr");
7788 /* extract colour space info */
7789 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
7790 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
7792 colorspace = "sRGB";
7795 colorspace = "GRAY";
7798 colorspace = "sYUV";
7806 /* colr is required, and only values 16, 17, and 18 are specified,
7807 so error if we have no colorspace */
7810 /* extract component mapping */
7811 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
7813 guint32 cmap_len = 0;
7815 cmap_len = QT_UINT32 (cmap->data);
7816 if (cmap_len >= 8) {
7817 /* normal box, subtract off header */
7819 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
7820 if (cmap_len % 4 == 0) {
7821 ncomp_map = (cmap_len / 4);
7822 comp_map = g_new0 (gint32, ncomp_map);
7823 for (i = 0; i < ncomp_map; i++) {
7826 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
7827 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
7828 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
7829 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
7834 /* extract channel definitions */
7835 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
7837 guint32 cdef_len = 0;
7839 cdef_len = QT_UINT32 (cdef->data);
7840 if (cdef_len >= 10) {
7841 /* normal box, subtract off header and len */
7843 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
7844 if (cdef_len % 6 == 0) {
7845 nchan_def = (cdef_len / 6);
7846 chan_def = g_new0 (gint32, nchan_def);
7847 for (i = 0; i < nchan_def; i++)
7849 for (i = 0; i < nchan_def; i++) {
7850 guint16 cn, typ, asoc;
7851 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
7852 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
7853 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
7854 if (cn < nchan_def) {
7857 chan_def[cn] = asoc;
7860 chan_def[cn] = 0; /* alpha */
7863 chan_def[cn] = -typ;
7871 gst_caps_set_simple (stream->caps,
7872 "num-components", G_TYPE_INT, ncomp, NULL);
7873 gst_caps_set_simple (stream->caps,
7874 "colorspace", G_TYPE_STRING, colorspace, NULL);
7877 GValue arr = { 0, };
7878 GValue elt = { 0, };
7880 g_value_init (&arr, GST_TYPE_ARRAY);
7881 g_value_init (&elt, G_TYPE_INT);
7882 for (i = 0; i < ncomp_map; i++) {
7883 g_value_set_int (&elt, comp_map[i]);
7884 gst_value_array_append_value (&arr, &elt);
7886 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
7887 "component-map", &arr);
7888 g_value_unset (&elt);
7889 g_value_unset (&arr);
7894 GValue arr = { 0, };
7895 GValue elt = { 0, };
7897 g_value_init (&arr, GST_TYPE_ARRAY);
7898 g_value_init (&elt, G_TYPE_INT);
7899 for (i = 0; i < nchan_def; i++) {
7900 g_value_set_int (&elt, chan_def[i]);
7901 gst_value_array_append_value (&arr, &elt);
7903 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
7904 "channel-definitions", &arr);
7905 g_value_unset (&elt);
7906 g_value_unset (&arr);
7910 /* some optional atoms */
7911 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
7912 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
7914 /* indicate possible fields in caps */
7916 data = (guint8 *) field->data + 8;
7918 gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
7919 (gint) * data, NULL);
7921 /* add codec_data if provided */
7926 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
7927 data = prefix->data;
7928 len = QT_UINT32 (data);
7931 buf = gst_buffer_new_and_alloc (len);
7932 gst_buffer_fill (buf, 0, data + 8, len);
7933 gst_caps_set_simple (stream->caps,
7934 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7935 gst_buffer_unref (buf);
7944 GstBuffer *seqh = NULL;
7945 guint8 *gamma_data = NULL;
7946 gint len = QT_UINT32 (stsd_data);
7948 qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
7950 gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
7951 QT_FP32 (gamma_data), NULL);
7954 /* sorry for the bad name, but we don't know what this is, other
7955 * than its own fourcc */
7956 gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
7960 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
7961 buf = gst_buffer_new_and_alloc (len);
7962 gst_buffer_fill (buf, 0, stsd_data, len);
7963 gst_caps_set_simple (stream->caps,
7964 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7965 gst_buffer_unref (buf);
7971 gst_caps_set_simple (stream->caps,
7972 "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
7979 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
7980 xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
7984 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
7988 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
7989 /* collect the headers and store them in a stream list so that we can
7990 * send them out first */
7991 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
8001 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
8002 ovc1 = qtdemux_tree_get_child_by_type (stsd, FOURCC_ovc1);
8005 ovc1_data = ovc1->data;
8006 ovc1_len = QT_UINT32 (ovc1_data);
8007 if (ovc1_len <= 198) {
8008 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
8011 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
8012 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
8013 gst_caps_set_simple (stream->caps,
8014 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8015 gst_buffer_unref (buf);
8023 GST_INFO_OBJECT (qtdemux,
8024 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
8025 GST_FOURCC_ARGS (fourcc), stream->caps);
8027 } else if (stream->subtype == FOURCC_soun) {
8028 int version, samplesize;
8029 guint16 compression_id;
8030 gboolean amrwb = FALSE;
8033 /* sample description entry (16) + sound sample description v0 (20) */
8037 version = QT_UINT32 (stsd_data + offset);
8038 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
8039 samplesize = QT_UINT16 (stsd_data + offset + 10);
8040 compression_id = QT_UINT16 (stsd_data + offset + 12);
8041 stream->rate = QT_FP32 (stsd_data + offset + 16);
8043 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
8044 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
8045 QT_UINT32 (stsd_data + offset + 4));
8046 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
8047 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
8048 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
8049 GST_LOG_OBJECT (qtdemux, "packet size: %d",
8050 QT_UINT16 (stsd_data + offset + 14));
8051 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
8053 if (compression_id == 0xfffe)
8054 stream->sampled = TRUE;
8056 /* first assume uncompressed audio */
8057 stream->bytes_per_sample = samplesize / 8;
8058 stream->samples_per_frame = stream->n_channels;
8059 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
8060 stream->samples_per_packet = stream->samples_per_frame;
8061 stream->bytes_per_packet = stream->bytes_per_sample;
8065 /* Yes, these have to be hard-coded */
8068 stream->samples_per_packet = 6;
8069 stream->bytes_per_packet = 1;
8070 stream->bytes_per_frame = 1 * stream->n_channels;
8071 stream->bytes_per_sample = 1;
8072 stream->samples_per_frame = 6 * stream->n_channels;
8077 stream->samples_per_packet = 3;
8078 stream->bytes_per_packet = 1;
8079 stream->bytes_per_frame = 1 * stream->n_channels;
8080 stream->bytes_per_sample = 1;
8081 stream->samples_per_frame = 3 * stream->n_channels;
8086 stream->samples_per_packet = 64;
8087 stream->bytes_per_packet = 34;
8088 stream->bytes_per_frame = 34 * stream->n_channels;
8089 stream->bytes_per_sample = 2;
8090 stream->samples_per_frame = 64 * stream->n_channels;
8096 stream->samples_per_packet = 1;
8097 stream->bytes_per_packet = 1;
8098 stream->bytes_per_frame = 1 * stream->n_channels;
8099 stream->bytes_per_sample = 1;
8100 stream->samples_per_frame = 1 * stream->n_channels;
8105 stream->samples_per_packet = 160;
8106 stream->bytes_per_packet = 33;
8107 stream->bytes_per_frame = 33 * stream->n_channels;
8108 stream->bytes_per_sample = 2;
8109 stream->samples_per_frame = 160 * stream->n_channels;
8116 if (version == 0x00010000) {
8117 /* sample description entry (16) + sound sample description v1 (20+16) */
8128 /* only parse extra decoding config for non-pcm audio */
8129 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
8130 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
8131 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
8132 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
8134 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
8135 stream->samples_per_packet);
8136 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
8137 stream->bytes_per_packet);
8138 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
8139 stream->bytes_per_frame);
8140 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
8141 stream->bytes_per_sample);
8143 if (!stream->sampled && stream->bytes_per_packet) {
8144 stream->samples_per_frame = (stream->bytes_per_frame /
8145 stream->bytes_per_packet) * stream->samples_per_packet;
8146 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
8147 stream->samples_per_frame);
8152 } else if (version == 0x00020000) {
8159 /* sample description entry (16) + sound sample description v2 (56) */
8163 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
8164 stream->rate = qtfp.fp;
8165 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
8167 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
8168 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
8169 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
8170 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
8171 QT_UINT32 (stsd_data + offset + 20));
8172 GST_LOG_OBJECT (qtdemux, "format flags: %X",
8173 QT_UINT32 (stsd_data + offset + 24));
8174 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
8175 QT_UINT32 (stsd_data + offset + 28));
8176 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
8177 QT_UINT32 (stsd_data + offset + 32));
8179 GST_WARNING_OBJECT (qtdemux, "unknown version %08x", version);
8182 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc,
8183 stsd_data + 32, len - 16, &codec);
8191 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
8193 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
8195 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
8197 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
8200 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
8201 gst_caps_set_simple (stream->caps,
8202 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE", NULL);
8209 const guint8 *owma_data;
8210 const gchar *codec_name = NULL;
8214 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
8215 /* FIXME this should also be gst_riff_strf_auds,
8216 * but the latter one is actually missing bits-per-sample :( */
8221 gint32 nSamplesPerSec;
8222 gint32 nAvgBytesPerSec;
8224 gint16 wBitsPerSample;
8229 GST_DEBUG_OBJECT (qtdemux, "parse owma");
8230 owma = qtdemux_tree_get_child_by_type (stsd, FOURCC_owma);
8233 owma_data = owma->data;
8234 owma_len = QT_UINT32 (owma_data);
8235 if (owma_len <= 54) {
8236 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
8239 wfex = (WAVEFORMATEX *) (owma_data + 36);
8240 buf = gst_buffer_new_and_alloc (owma_len - 54);
8241 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
8242 if (wfex->wFormatTag == 0x0161) {
8243 codec_name = "Windows Media Audio";
8245 } else if (wfex->wFormatTag == 0x0162) {
8246 codec_name = "Windows Media Audio 9 Pro";
8248 } else if (wfex->wFormatTag == 0x0163) {
8249 codec_name = "Windows Media Audio 9 Lossless";
8250 /* is that correct? gstffmpegcodecmap.c is missing it, but
8251 * fluendo codec seems to support it */
8255 gst_caps_set_simple (stream->caps,
8256 "codec_data", GST_TYPE_BUFFER, buf,
8257 "wmaversion", G_TYPE_INT, version,
8258 "block_align", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->nBlockAlign),
8259 "bitrate", G_TYPE_INT, GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec),
8260 "width", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
8261 "depth", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
8263 gst_buffer_unref (buf);
8267 codec = g_strdup (codec_name);
8279 list = gst_tag_list_new_empty ();
8280 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
8281 GST_TAG_AUDIO_CODEC, codec, NULL);
8285 /* some bitrate info may have ended up in caps */
8286 s = gst_caps_get_structure (stream->caps, 0);
8287 gst_structure_get_int (s, "bitrate", &bitrate);
8289 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
8293 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
8297 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
8299 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
8301 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
8305 /* If the fourcc's bottom 16 bits gives 'sm', then the top
8306 16 bits is a byte-swapped wave-style codec identifier,
8307 and we can find a WAVE header internally to a 'wave' atom here.
8308 This can more clearly be thought of as 'ms' as the top 16 bits, and a
8309 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
8312 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
8313 if (len < offset + 20) {
8314 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
8316 guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
8317 const guint8 *data = stsd_data + offset + 16;
8319 GNode *waveheadernode;
8321 wavenode = g_node_new ((guint8 *) data);
8322 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
8323 const guint8 *waveheader;
8326 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
8327 if (waveheadernode) {
8328 waveheader = (const guint8 *) waveheadernode->data;
8329 headerlen = QT_UINT32 (waveheader);
8331 if (headerlen > 8) {
8332 gst_riff_strf_auds *header = NULL;
8333 GstBuffer *headerbuf;
8339 headerbuf = gst_buffer_new_and_alloc (headerlen);
8340 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
8342 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
8343 headerbuf, &header, &extra)) {
8344 gst_caps_unref (stream->caps);
8345 /* FIXME: Need to do something with the channel reorder map */
8346 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
8347 header, extra, NULL, NULL, NULL);
8350 gst_buffer_unref (extra);
8355 GST_DEBUG ("Didn't find waveheadernode for this codec");
8357 g_node_destroy (wavenode);
8360 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
8364 /* FIXME: what is in the chunk? */
8367 gint len = QT_UINT32 (stsd_data);
8369 /* seems to be always = 116 = 0x74 */
8375 gint len = QT_UINT32 (stsd_data);
8378 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
8380 gst_buffer_fill (buf, 0, stsd_data + 0x4C, len - 0x4C);
8381 gst_caps_set_simple (stream->caps,
8382 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8383 gst_buffer_unref (buf);
8385 gst_caps_set_simple (stream->caps,
8386 "samplesize", G_TYPE_INT, samplesize, NULL);
8391 GNode *alac, *wave = NULL;
8393 /* apparently, m4a has this atom appended directly in the stsd entry,
8394 * while mov has it in a wave atom */
8395 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
8397 /* alac now refers to stsd entry atom */
8398 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
8400 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
8402 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
8405 const guint8 *alac_data = alac->data;
8406 gint len = QT_UINT32 (alac->data);
8410 GST_DEBUG_OBJECT (qtdemux,
8411 "discarding alac atom with unexpected len %d", len);
8413 /* codec-data contains alac atom size and prefix,
8414 * ffmpeg likes it that way, not quite gst-ish though ...*/
8415 buf = gst_buffer_new_and_alloc (len);
8416 gst_buffer_fill (buf, 0, alac->data, len);
8417 gst_caps_set_simple (stream->caps,
8418 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8419 gst_buffer_unref (buf);
8421 stream->bytes_per_frame = QT_UINT32 (alac_data + 12);
8422 stream->n_channels = QT_UINT8 (alac_data + 21);
8423 stream->rate = QT_UINT32 (alac_data + 32);
8426 gst_caps_set_simple (stream->caps,
8427 "samplesize", G_TYPE_INT, samplesize, NULL);
8435 gint len = QT_UINT32 (stsd_data);
8438 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
8441 gst_buffer_fill (buf, 0, stsd_data + 0x34, len - 0x34);
8443 /* If we have enough data, let's try to get the 'damr' atom. See
8444 * the 3GPP container spec (26.244) for more details. */
8445 if ((len - 0x34) > 8 &&
8446 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
8448 list = gst_tag_list_new_empty ();
8449 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
8450 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
8453 gst_caps_set_simple (stream->caps,
8454 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8455 gst_buffer_unref (buf);
8460 GST_INFO_OBJECT (qtdemux,
8461 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
8465 GST_INFO_OBJECT (qtdemux,
8466 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
8467 GST_FOURCC_ARGS (fourcc), stream->caps);
8469 } else if (stream->subtype == FOURCC_strm) {
8470 if (fourcc == FOURCC_rtsp) {
8471 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
8473 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
8474 GST_FOURCC_ARGS (fourcc));
8475 goto unknown_stream;
8477 stream->sampled = TRUE;
8478 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
8479 || stream->subtype == FOURCC_sbtl) {
8481 stream->sampled = TRUE;
8482 stream->sparse = TRUE;
8487 qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
8489 list = gst_tag_list_new_empty ();
8490 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
8491 GST_TAG_SUBTITLE_CODEC, codec, NULL);
8496 /* hunt for sort-of codec data */
8503 /* look for palette in a stsd->mp4s->esds sub-atom */
8504 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
8506 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
8509 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
8513 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
8517 GST_INFO_OBJECT (qtdemux,
8518 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
8521 GST_INFO_OBJECT (qtdemux,
8522 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
8523 GST_FOURCC_ARGS (fourcc), stream->caps);
8525 /* everything in 1 sample */
8526 stream->sampled = TRUE;
8529 qtdemux_generic_caps (qtdemux, stream, fourcc, stsd_data, &codec);
8531 if (stream->caps == NULL)
8532 goto unknown_stream;
8535 list = gst_tag_list_new_empty ();
8536 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
8537 GST_TAG_SUBTITLE_CODEC, codec, NULL);
8543 /* promote to sampled format */
8544 if (stream->fourcc == FOURCC_samr) {
8545 /* force mono 8000 Hz for AMR */
8546 stream->sampled = TRUE;
8547 stream->n_channels = 1;
8548 stream->rate = 8000;
8549 } else if (stream->fourcc == FOURCC_sawb) {
8550 /* force mono 16000 Hz for AMR-WB */
8551 stream->sampled = TRUE;
8552 stream->n_channels = 1;
8553 stream->rate = 16000;
8554 } else if (stream->fourcc == FOURCC_mp4a) {
8555 stream->sampled = TRUE;
8558 /* collect sample information */
8559 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
8560 goto samples_failed;
8562 if (qtdemux->fragmented) {
8566 /* need all moov samples as basis; probably not many if any at all */
8567 /* prevent moof parsing taking of at this time */
8568 offset = qtdemux->moof_offset;
8569 qtdemux->moof_offset = 0;
8570 if (stream->n_samples &&
8571 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
8572 qtdemux->moof_offset = offset;
8573 goto samples_failed;
8575 qtdemux->moof_offset = 0;
8576 /* movie duration more reliable in this case (e.g. mehd) */
8577 if (qtdemux->segment.duration &&
8578 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
8579 stream->duration = gst_util_uint64_scale (qtdemux->segment.duration,
8580 stream->timescale, GST_SECOND);
8581 /* need defaults for fragments */
8582 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
8585 /* configure segments */
8586 if (!qtdemux_parse_segments (qtdemux, stream, trak))
8587 goto segments_failed;
8589 /* add some language tag, if useful */
8590 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
8591 strcmp (stream->lang_id, "und")) {
8592 const gchar *lang_code;
8595 list = gst_tag_list_new_empty ();
8597 /* convert ISO 639-2 code to ISO 639-1 */
8598 lang_code = gst_tag_get_language_code (stream->lang_id);
8599 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
8600 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
8603 /* now we are ready to add the stream */
8604 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
8605 goto too_many_streams;
8607 if (!qtdemux->got_moov) {
8608 stream->pending_tags = list;
8609 qtdemux->streams[qtdemux->n_streams] = stream;
8610 qtdemux->n_streams++;
8611 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
8619 GST_INFO_OBJECT (qtdemux, "skip disabled track");
8626 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8627 (_("This file is corrupt and cannot be played.")), (NULL));
8634 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
8642 /* we posted an error already */
8643 /* free stbl sub-atoms */
8644 gst_qtdemux_stbl_free (stream);
8651 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
8659 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
8660 GST_FOURCC_ARGS (stream->subtype));
8667 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
8668 (_("This file contains too many streams. Only playing first %d"),
8669 GST_QTDEMUX_MAX_STREAMS), (NULL));
8674 /* If we can estimate the overall bitrate, and don't have information about the
8675 * stream bitrate for exactly one stream, this guesses the stream bitrate as
8676 * the overall bitrate minus the sum of the bitrates of all other streams. This
8677 * should be useful for the common case where we have one audio and one video
8678 * stream and can estimate the bitrate of one, but not the other. */
8680 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
8682 QtDemuxStream *stream = NULL;
8683 gint64 size, duration, sys_bitrate, sum_bitrate = 0;
8687 if (qtdemux->fragmented)
8690 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
8692 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
8694 GST_DEBUG_OBJECT (qtdemux,
8695 "Size in bytes of the stream not known - bailing");
8699 /* Subtract the header size */
8700 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
8701 size, qtdemux->header_size);
8703 if (size < qtdemux->header_size)
8706 size = size - qtdemux->header_size;
8708 if (!gst_qtdemux_get_duration (qtdemux, &duration) ||
8709 duration == GST_CLOCK_TIME_NONE) {
8710 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
8714 for (i = 0; i < qtdemux->n_streams; i++) {
8715 switch (qtdemux->streams[i]->subtype) {
8718 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
8719 qtdemux->streams[i]->caps);
8720 /* retrieve bitrate, prefer avg then max */
8722 if (qtdemux->streams[i]->pending_tags) {
8723 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
8724 GST_TAG_MAXIMUM_BITRATE, &bitrate);
8725 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
8726 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
8727 GST_TAG_NOMINAL_BITRATE, &bitrate);
8728 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
8729 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
8730 GST_TAG_BITRATE, &bitrate);
8731 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
8734 sum_bitrate += bitrate;
8737 GST_DEBUG_OBJECT (qtdemux,
8738 ">1 stream with unknown bitrate - bailing");
8741 stream = qtdemux->streams[i];
8745 /* For other subtypes, we assume no significant impact on bitrate */
8751 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
8755 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
8757 if (sys_bitrate < sum_bitrate) {
8758 /* This can happen, since sum_bitrate might be derived from maximum
8759 * bitrates and not average bitrates */
8760 GST_DEBUG_OBJECT (qtdemux,
8761 "System bitrate less than sum bitrate - bailing");
8765 bitrate = sys_bitrate - sum_bitrate;
8766 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
8767 ", Stream bitrate = %u", sys_bitrate, bitrate);
8769 if (!stream->pending_tags)
8770 stream->pending_tags = gst_tag_list_new_empty ();
8772 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
8773 GST_TAG_BITRATE, bitrate, NULL);
8776 static GstFlowReturn
8777 qtdemux_prepare_streams (GstQTDemux * qtdemux)
8780 GstFlowReturn ret = GST_FLOW_OK;
8782 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
8784 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
8785 QtDemuxStream *stream = qtdemux->streams[i];
8786 guint32 sample_num = 0;
8790 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
8791 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
8793 if (qtdemux->fragmented) {
8794 /* need all moov samples first */
8795 GST_OBJECT_LOCK (qtdemux);
8796 while (stream->n_samples == 0)
8797 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
8799 GST_OBJECT_UNLOCK (qtdemux);
8801 /* discard any stray moof */
8802 qtdemux->moof_offset = 0;
8805 /* prepare braking */
8806 if (ret != GST_FLOW_ERROR)
8809 /* in pull mode, we should have parsed some sample info by now;
8810 * and quite some code will not handle no samples.
8811 * in push mode, we'll just have to deal with it */
8812 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
8813 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
8814 gst_qtdemux_remove_stream (qtdemux, i);
8819 /* parse number of initial sample to set frame rate cap */
8820 while (sample_num < stream->n_samples && sample_num < samples) {
8821 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
8825 /* collect and sort durations */
8826 samples = MIN (stream->stbl_index + 1, samples);
8827 GST_DEBUG_OBJECT (qtdemux, "%d samples for framerate", samples);
8829 durations = g_array_sized_new (FALSE, FALSE, sizeof (guint32), samples);
8831 while (sample_num < samples) {
8832 g_array_append_val (durations, stream->samples[sample_num].duration);
8835 g_array_sort (durations, less_than);
8836 stream->min_duration = g_array_index (durations, guint32, samples / 2);
8837 g_array_free (durations, TRUE);
8844 static GstFlowReturn
8845 qtdemux_expose_streams (GstQTDemux * qtdemux)
8848 GstFlowReturn ret = GST_FLOW_OK;
8849 GSList *oldpads = NULL;
8852 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
8854 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
8855 QtDemuxStream *stream = qtdemux->streams[i];
8856 GstPad *oldpad = stream->pad;
8859 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
8860 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
8862 if ((stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl) &&
8863 stream->track_id == qtdemux->chapters_track_id) {
8864 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
8865 so that it doesn't look like a subtitle track */
8866 gst_qtdemux_remove_stream (qtdemux, i);
8871 /* now we have all info and can expose */
8872 list = stream->pending_tags;
8873 stream->pending_tags = NULL;
8875 oldpads = g_slist_prepend (oldpads, oldpad);
8876 gst_qtdemux_add_stream (qtdemux, stream, list);
8879 gst_qtdemux_guess_bitrate (qtdemux);
8881 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
8883 for (iter = oldpads; iter; iter = g_slist_next (iter)) {
8884 GstPad *oldpad = iter->data;
8886 gst_pad_push_event (oldpad, gst_event_new_eos ());
8887 gst_pad_set_active (oldpad, FALSE);
8888 gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
8889 gst_object_unref (oldpad);
8892 /* check if we should post a redirect in case there is a single trak
8893 * and it is a redirecting trak */
8894 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
8897 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
8898 "an external content");
8899 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
8900 gst_structure_new ("redirect",
8901 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
8903 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
8904 qtdemux->posted_redirect = TRUE;
8907 for (i = 0; i < qtdemux->n_streams; i++) {
8908 QtDemuxStream *stream = qtdemux->streams[i];
8910 qtdemux_do_allocation (qtdemux, stream);
8913 qtdemux->exposed = TRUE;
8917 /* check if major or compatible brand is 3GP */
8918 static inline gboolean
8919 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
8922 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
8923 GST_MAKE_FOURCC ('3', 'g', 0, 0));
8924 } else if (qtdemux->comp_brands != NULL) {
8928 gboolean res = FALSE;
8930 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
8934 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
8935 GST_MAKE_FOURCC ('3', 'g', 0, 0));
8939 gst_buffer_unmap (qtdemux->comp_brands, &map);
8946 /* check if tag is a spec'ed 3GP tag keyword storing a string */
8947 static inline gboolean
8948 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
8950 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
8951 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
8952 || fourcc == FOURCC_albm;
8956 qtdemux_tag_add_location (GstQTDemux * qtdemux, const char *tag,
8957 const char *dummy, GNode * node)
8959 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
8963 gdouble longitude, latitude, altitude;
8966 len = QT_UINT32 (node->data);
8973 /* TODO: language code skipped */
8975 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
8978 /* do not alarm in trivial case, but bail out otherwise */
8979 if (*(data + offset) != 0) {
8980 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
8984 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8985 GST_TAG_GEO_LOCATION_NAME, name, NULL);
8986 offset += strlen (name);
8990 if (len < offset + 2 + 4 + 4 + 4)
8993 /* +1 +1 = skip null-terminator and location role byte */
8995 /* table in spec says unsigned, semantics say negative has meaning ... */
8996 longitude = QT_SFP32 (data + offset);
8999 latitude = QT_SFP32 (data + offset);
9002 altitude = QT_SFP32 (data + offset);
9004 /* one invalid means all are invalid */
9005 if (longitude >= -180.0 && longitude <= 180.0 &&
9006 latitude >= -90.0 && latitude <= 90.0) {
9007 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9008 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
9009 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
9010 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
9013 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
9020 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
9027 qtdemux_tag_add_year (GstQTDemux * qtdemux, const char *tag, const char *dummy,
9034 len = QT_UINT32 (node->data);
9038 y = QT_UINT16 ((guint8 *) node->data + 12);
9040 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
9043 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
9045 date = g_date_new_dmy (1, 1, y);
9046 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, date, NULL);
9051 qtdemux_tag_add_classification (GstQTDemux * qtdemux, const char *tag,
9052 const char *dummy, GNode * node)
9055 char *tag_str = NULL;
9060 len = QT_UINT32 (node->data);
9065 entity = (guint8 *) node->data + offset;
9066 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
9067 GST_DEBUG_OBJECT (qtdemux,
9068 "classification info: %c%c%c%c invalid classification entity",
9069 entity[0], entity[1], entity[2], entity[3]);
9074 table = QT_UINT16 ((guint8 *) node->data + offset);
9076 /* Language code skipped */
9080 /* Tag format: "XXXX://Y[YYYY]/classification info string"
9081 * XXXX: classification entity, fixed length 4 chars.
9082 * Y[YYYY]: classification table, max 5 chars.
9084 tag_str = g_strdup_printf ("----://%u/%s",
9085 table, (char *) node->data + offset);
9087 /* memcpy To be sure we're preserving byte order */
9088 memcpy (tag_str, entity, 4);
9089 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
9091 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_APPEND, tag,
9101 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
9107 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, const char *tag,
9108 const char *dummy, GNode * node)
9110 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
9116 gboolean ret = TRUE;
9117 const gchar *charset = NULL;
9119 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9121 len = QT_UINT32 (data->data);
9122 type = QT_UINT32 ((guint8 *) data->data + 8);
9123 if (type == 0x00000001 && len > 16) {
9124 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
9127 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
9128 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s,
9132 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
9136 len = QT_UINT32 (node->data);
9137 type = QT_UINT32 ((guint8 *) node->data + 4);
9138 if ((type >> 24) == 0xa9) {
9142 /* Type starts with the (C) symbol, so the next data is a list
9143 * of (string size(16), language code(16), string) */
9145 str_len = QT_UINT16 ((guint8 *) node->data + 8);
9146 lang_code = QT_UINT16 ((guint8 *) node->data + 10);
9148 /* the string + fourcc + size + 2 16bit fields,
9149 * means that there are more tags in this atom */
9150 if (len > str_len + 8 + 4) {
9151 /* TODO how to represent the same tag in different languages? */
9152 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
9153 "text alternatives, reading only first one");
9157 len = str_len + 8 + 4; /* remove trailing strings that we don't use */
9158 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
9160 if (lang_code < 0x800) { /* MAC encoded string */
9163 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
9164 QT_FOURCC ((guint8 *) node->data + 4))) {
9165 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
9167 /* we go for 3GP style encoding if major brands claims so,
9168 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
9169 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
9170 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
9171 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
9173 /* 16-bit Language code is ignored here as well */
9174 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
9181 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
9182 ret = FALSE; /* may have to fallback */
9187 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
9188 charset, NULL, NULL, &err);
9190 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
9191 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
9196 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
9197 len - offset, env_vars);
9200 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
9201 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s, NULL);
9205 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
9212 qtdemux_tag_add_str (GstQTDemux * qtdemux, const char *tag,
9213 const char *dummy, GNode * node)
9215 qtdemux_tag_add_str_full (qtdemux, tag, dummy, node);
9219 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, const char *tag,
9220 const char *dummy, GNode * node)
9222 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
9224 char *s, *t, *k = NULL;
9229 /* first try normal string tag if major brand not 3GP */
9230 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
9231 if (!qtdemux_tag_add_str_full (qtdemux, tag, dummy, node)) {
9232 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
9233 * let's try it 3gpp way after minor safety check */
9235 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
9241 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
9245 len = QT_UINT32 (data);
9249 count = QT_UINT8 (data + 14);
9251 for (; count; count--) {
9254 if (offset + 1 > len)
9256 slen = QT_UINT8 (data + offset);
9258 if (offset + slen > len)
9260 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
9263 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
9265 t = g_strjoin (",", k, s, NULL);
9273 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
9280 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
9281 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, k, NULL);
9290 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
9296 qtdemux_tag_add_num (GstQTDemux * qtdemux, const char *tag1,
9297 const char *tag2, GNode * node)
9304 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9306 len = QT_UINT32 (data->data);
9307 type = QT_UINT32 ((guint8 *) data->data + 8);
9308 if (type == 0x00000000 && len >= 22) {
9309 n1 = QT_UINT16 ((guint8 *) data->data + 18);
9310 n2 = QT_UINT16 ((guint8 *) data->data + 20);
9312 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
9313 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9317 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
9318 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9326 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
9334 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9336 len = QT_UINT32 (data->data);
9337 type = QT_UINT32 ((guint8 *) data->data + 8);
9338 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
9339 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
9340 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
9341 n1 = QT_UINT16 ((guint8 *) data->data + 16);
9343 /* do not add bpm=0 */
9344 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
9345 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9346 tag1, (gdouble) n1, NULL);
9353 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, const char *tag1,
9354 const char *dummy, GNode * node)
9361 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9363 len = QT_UINT32 (data->data);
9364 type = QT_UINT32 ((guint8 *) data->data + 8);
9365 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
9366 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
9367 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
9368 num = QT_UINT32 ((guint8 *) data->data + 16);
9370 /* do not add num=0 */
9371 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
9372 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9380 qtdemux_tag_add_covr (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
9388 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9390 len = QT_UINT32 (data->data);
9391 type = QT_UINT32 ((guint8 *) data->data + 8);
9392 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
9393 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
9395 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
9396 len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
9397 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
9398 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9399 tag1, sample, NULL);
9400 gst_sample_unref (sample);
9407 qtdemux_tag_add_date (GstQTDemux * qtdemux, const char *tag, const char *dummy,
9415 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9417 len = QT_UINT32 (data->data);
9418 type = QT_UINT32 ((guint8 *) data->data + 8);
9419 if (type == 0x00000001 && len > 16) {
9420 guint y, m = 1, d = 1;
9423 s = g_strndup ((char *) data->data + 16, len - 16);
9424 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
9425 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
9426 if (ret >= 1 && y > 1500 && y < 3000) {
9429 date = g_date_new_dmy (d, m, y);
9430 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag,
9434 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
9442 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, const char *tag, const char *dummy,
9447 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9449 /* re-route to normal string tag if major brand says so
9450 * or no data atom and compatible brand suggests so */
9451 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
9452 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
9453 qtdemux_tag_add_str (qtdemux, tag, dummy, node);
9460 len = QT_UINT32 (data->data);
9461 type = QT_UINT32 ((guint8 *) data->data + 8);
9462 if (type == 0x00000000 && len >= 18) {
9463 n = QT_UINT16 ((guint8 *) data->data + 16);
9467 genre = gst_tag_id3_genre_get (n - 1);
9468 if (genre != NULL) {
9469 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
9470 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9479 qtdemux_add_double_tag_from_str (GstQTDemux * demux, const gchar * tag,
9480 guint8 * data, guint32 datasize)
9485 /* make a copy to have \0 at the end */
9486 datacopy = g_strndup ((gchar *) data, datasize);
9488 /* convert the str to double */
9489 if (sscanf (datacopy, "%lf", &value) == 1) {
9490 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
9491 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_REPLACE, tag, value, NULL);
9493 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
9501 qtdemux_tag_add_revdns (GstQTDemux * demux, const char *tag,
9502 const char *tag_bis, GNode * node)
9511 const gchar *meanstr;
9512 const gchar *namestr;
9514 /* checking the whole ---- atom size for consistency */
9515 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
9516 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
9520 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
9522 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
9526 meansize = QT_UINT32 (mean->data);
9527 if (meansize <= 12) {
9528 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
9531 meanstr = ((gchar *) mean->data) + 12;
9534 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
9536 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
9540 namesize = QT_UINT32 (name->data);
9541 if (namesize <= 12) {
9542 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
9545 namestr = ((gchar *) name->data) + 12;
9553 * uint24 - data type
9557 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9559 GST_WARNING_OBJECT (demux, "No data atom in this tag");
9562 datasize = QT_UINT32 (data->data);
9563 if (datasize <= 16) {
9564 GST_WARNING_OBJECT (demux, "Data atom too small");
9567 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
9569 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
9570 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
9573 const gchar name[28];
9574 const gchar tag[28];
9577 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
9578 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
9579 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
9580 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
9581 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
9582 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
9583 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
9584 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
9588 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
9589 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
9590 switch (gst_tag_get_type (tags[i].tag)) {
9592 qtdemux_add_double_tag_from_str (demux, tags[i].tag,
9593 ((guint8 *) data->data) + 16, datasize - 16);
9596 qtdemux_tag_add_str (demux, tags[i].tag, NULL, node);
9605 if (i == G_N_ELEMENTS (tags))
9615 #ifndef GST_DISABLE_GST_DEBUG
9620 meanstr_dbg = g_strndup (meanstr, meansize);
9621 namestr_dbg = g_strndup (namestr, namesize);
9623 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
9624 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
9626 g_free (namestr_dbg);
9627 g_free (meanstr_dbg);
9634 qtdemux_tag_add_id32 (GstQTDemux * demux, const char *tag,
9635 const char *tag_bis, GNode * node)
9640 GstTagList *taglist = NULL;
9642 GST_LOG_OBJECT (demux, "parsing ID32");
9645 len = GST_READ_UINT32_BE (data);
9647 /* need at least full box and language tag */
9651 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
9652 gst_buffer_fill (buf, 0, data + 14, len - 14);
9654 taglist = gst_tag_list_from_id3v2_tag (buf);
9656 GST_LOG_OBJECT (demux, "parsing ok");
9657 gst_tag_list_insert (demux->tag_list, taglist, GST_TAG_MERGE_KEEP);
9659 GST_LOG_OBJECT (demux, "parsing failed");
9663 gst_tag_list_unref (taglist);
9665 gst_buffer_unref (buf);
9668 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux,
9669 const char *tag, const char *tag_bis, GNode * node);
9672 FOURCC_pcst -> if media is a podcast -> bool
9673 FOURCC_cpil -> if media is part of a compilation -> bool
9674 FOURCC_pgap -> if media is part of a gapless context -> bool
9675 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
9681 const gchar *gst_tag;
9682 const gchar *gst_tag_bis;
9683 const GstQTDemuxAddTagFunc func;
9686 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
9687 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
9688 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
9689 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
9690 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
9691 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
9692 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
9693 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
9694 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
9695 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
9696 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
9697 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
9698 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
9699 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
9700 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
9701 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
9702 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
9703 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
9704 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
9705 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
9706 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
9707 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
9708 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
9709 qtdemux_tag_add_num}, {
9710 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
9711 qtdemux_tag_add_num}, {
9712 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
9713 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
9714 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
9715 FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
9716 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
9717 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
9718 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
9719 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
9720 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
9721 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
9722 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
9723 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
9724 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
9725 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
9726 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
9727 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
9728 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
9729 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
9730 qtdemux_tag_add_classification}, {
9732 /* This is a special case, some tags are stored in this
9733 * 'reverse dns naming', according to:
9734 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
9737 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
9738 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
9739 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
9743 qtdemux_tag_add_blob (GNode * node, GstQTDemux * demux)
9756 len = QT_UINT32 (data);
9757 buf = gst_buffer_new_and_alloc (len);
9758 gst_buffer_fill (buf, 0, data, len);
9760 /* heuristic to determine style of tag */
9761 if (QT_FOURCC (data + 4) == FOURCC_____ ||
9762 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
9764 else if (demux->major_brand == FOURCC_qt__)
9765 style = "quicktime";
9766 /* fall back to assuming iso/3gp tag style */
9770 /* santize the name for the caps. */
9771 for (i = 0; i < 4; i++) {
9772 guint8 d = data[4 + i];
9773 if (g_ascii_isalnum (d))
9774 ndata[i] = g_ascii_tolower (d);
9779 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
9780 ndata[0], ndata[1], ndata[2], ndata[3]);
9781 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
9783 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
9784 sample = gst_sample_new (buf, NULL, NULL, s);
9785 gst_buffer_unref (buf);
9786 g_free (media_type);
9788 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
9791 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_APPEND,
9792 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
9794 gst_sample_unref (sample);
9798 qtdemux_parse_udta (GstQTDemux * qtdemux, GNode * udta)
9806 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
9808 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
9810 GST_LOG_OBJECT (qtdemux, "no ilst");
9815 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
9818 GST_DEBUG_OBJECT (qtdemux, "new tag list");
9819 if (!qtdemux->tag_list) {
9820 qtdemux->tag_list = gst_tag_list_new_empty ();
9821 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
9823 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
9827 while (i < G_N_ELEMENTS (add_funcs)) {
9828 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
9832 len = QT_UINT32 (node->data);
9834 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
9835 GST_FOURCC_ARGS (add_funcs[i].fourcc));
9837 add_funcs[i].func (qtdemux, add_funcs[i].gst_tag,
9838 add_funcs[i].gst_tag_bis, node);
9840 g_node_destroy (node);
9846 /* parsed nodes have been removed, pass along remainder as blob */
9847 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
9848 (GNodeForeachFunc) qtdemux_tag_add_blob, qtdemux);
9850 /* parse up XMP_ node if existing */
9851 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
9854 GstTagList *taglist;
9856 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
9857 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
9858 taglist = gst_tag_list_from_xmp_buffer (buf);
9859 gst_buffer_unref (buf);
9861 qtdemux_handle_xmp_taglist (qtdemux, taglist);
9863 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
9870 GstStructure *structure; /* helper for sort function */
9872 guint min_req_bitrate;
9873 guint min_req_qt_version;
9877 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
9879 GstQtReference *ref_a = (GstQtReference *) a;
9880 GstQtReference *ref_b = (GstQtReference *) b;
9882 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
9883 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
9885 /* known bitrates go before unknown; higher bitrates go first */
9886 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
9889 /* sort the redirects and post a message for the application.
9892 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
9894 GstQtReference *best;
9897 GValue list_val = { 0, };
9900 g_assert (references != NULL);
9902 references = g_list_sort (references, qtdemux_redirects_sort_func);
9904 best = (GstQtReference *) references->data;
9906 g_value_init (&list_val, GST_TYPE_LIST);
9908 for (l = references; l != NULL; l = l->next) {
9909 GstQtReference *ref = (GstQtReference *) l->data;
9910 GValue struct_val = { 0, };
9912 ref->structure = gst_structure_new ("redirect",
9913 "new-location", G_TYPE_STRING, ref->location, NULL);
9915 if (ref->min_req_bitrate > 0) {
9916 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
9917 ref->min_req_bitrate, NULL);
9920 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
9921 g_value_set_boxed (&struct_val, ref->structure);
9922 gst_value_list_append_value (&list_val, &struct_val);
9923 g_value_unset (&struct_val);
9924 /* don't free anything here yet, since we need best->structure below */
9927 g_assert (best != NULL);
9928 s = gst_structure_copy (best->structure);
9930 if (g_list_length (references) > 1) {
9931 gst_structure_set_value (s, "locations", &list_val);
9934 g_value_unset (&list_val);
9936 for (l = references; l != NULL; l = l->next) {
9937 GstQtReference *ref = (GstQtReference *) l->data;
9939 gst_structure_free (ref->structure);
9940 g_free (ref->location);
9943 g_list_free (references);
9945 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
9946 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
9947 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
9948 qtdemux->posted_redirect = TRUE;
9951 /* look for redirect nodes, collect all redirect information and
9955 qtdemux_parse_redirects (GstQTDemux * qtdemux)
9957 GNode *rmra, *rmda, *rdrf;
9959 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
9961 GList *redirects = NULL;
9963 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
9965 GstQtReference ref = { NULL, NULL, 0, 0 };
9968 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
9969 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
9970 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
9971 ref.min_req_bitrate);
9974 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
9975 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
9976 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
9978 #ifndef GST_DISABLE_GST_DEBUG
9979 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
9981 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
9983 GST_LOG_OBJECT (qtdemux,
9984 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
9985 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
9986 bitmask, check_type);
9987 if (package == FOURCC_qtim && check_type == 0) {
9988 ref.min_req_qt_version = version;
9992 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
9997 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
9998 ref_data = (guint8 *) rdrf->data + 20;
9999 if (ref_type == FOURCC_alis) {
10000 guint record_len, record_version, fn_len;
10002 /* MacOSX alias record, google for alias-layout.txt */
10003 record_len = QT_UINT16 (ref_data + 4);
10004 record_version = QT_UINT16 (ref_data + 4 + 2);
10005 fn_len = QT_UINT8 (ref_data + 50);
10006 if (record_len > 50 && record_version == 2 && fn_len > 0) {
10007 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
10009 } else if (ref_type == FOURCC_url_) {
10010 ref.location = g_strdup ((gchar *) ref_data);
10012 GST_DEBUG_OBJECT (qtdemux,
10013 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
10014 GST_FOURCC_ARGS (ref_type));
10016 if (ref.location != NULL) {
10017 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
10018 redirects = g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
10020 GST_WARNING_OBJECT (qtdemux,
10021 "Failed to extract redirect location from rdrf atom");
10025 /* look for others */
10026 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
10029 if (redirects != NULL) {
10030 qtdemux_process_redirects (qtdemux, redirects);
10036 static GstTagList *
10037 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
10041 if (tags == NULL) {
10042 tags = gst_tag_list_new_empty ();
10043 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
10046 if (qtdemux->major_brand == FOURCC_mjp2)
10047 fmt = "Motion JPEG 2000";
10048 else if ((qtdemux->major_brand & 0xffff) == GST_MAKE_FOURCC ('3', 'g', 0, 0))
10050 else if (qtdemux->major_brand == FOURCC_qt__)
10052 else if (qtdemux->fragmented)
10055 fmt = "ISO MP4/M4A";
10057 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
10058 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
10060 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
10066 /* we have read th complete moov node now.
10067 * This function parses all of the relevant info, creates the traks and
10068 * prepares all data structures for playback
10071 qtdemux_parse_tree (GstQTDemux * qtdemux)
10078 guint64 creation_time;
10079 GstDateTime *datetime = NULL;
10082 /* make sure we have a usable taglist */
10083 if (!qtdemux->tag_list) {
10084 qtdemux->tag_list = gst_tag_list_new_empty ();
10085 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
10087 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
10090 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
10091 if (mvhd == NULL) {
10092 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
10093 return qtdemux_parse_redirects (qtdemux);
10096 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
10097 if (version == 1) {
10098 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
10099 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
10100 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
10101 } else if (version == 0) {
10102 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
10103 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
10104 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
10106 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
10110 /* Moving qt creation time (secs since 1904) to unix time */
10111 if (creation_time != 0) {
10112 /* Try to use epoch first as it should be faster and more commonly found */
10113 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
10116 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
10117 /* some data cleansing sanity */
10118 g_get_current_time (&now);
10119 if (now.tv_sec + 24 * 3600 < creation_time) {
10120 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
10122 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
10125 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
10126 GDateTime *dt, *dt_local;
10128 dt = g_date_time_add_seconds (base_dt, creation_time);
10129 dt_local = g_date_time_to_local (dt);
10130 datetime = gst_date_time_new_from_g_date_time (dt_local);
10132 g_date_time_unref (base_dt);
10133 g_date_time_unref (dt);
10137 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
10138 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
10140 gst_date_time_unref (datetime);
10143 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
10144 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
10146 /* check for fragmented file and get some (default) data */
10147 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
10150 GstByteReader mehd_data;
10152 /* let track parsing or anyone know weird stuff might happen ... */
10153 qtdemux->fragmented = TRUE;
10155 /* compensate for total duration */
10156 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
10158 qtdemux_parse_mehd (qtdemux, &mehd_data);
10161 /* parse all traks */
10162 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
10164 qtdemux_parse_trak (qtdemux, trak);
10165 /* iterate all siblings */
10166 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
10169 /* set duration in the segment info */
10170 gst_qtdemux_get_duration (qtdemux, &duration);
10172 qtdemux->segment.duration = duration;
10173 /* also do not exceed duration; stop is set that way post seek anyway,
10174 * and segment activation falls back to duration,
10175 * whereas loop only checks stop, so let's align this here as well */
10176 qtdemux->segment.stop = duration;
10180 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
10182 qtdemux_parse_udta (qtdemux, udta);
10184 GST_LOG_OBJECT (qtdemux, "No udta node found.");
10187 /* maybe also some tags in meta box */
10188 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
10190 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
10191 qtdemux_parse_udta (qtdemux, udta);
10193 GST_LOG_OBJECT (qtdemux, "No meta node found.");
10196 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
10201 /* taken from ffmpeg */
10203 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
10215 len = (len << 7) | (c & 0x7f);
10223 /* this can change the codec originally present in @list */
10225 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
10226 GNode * esds, GstTagList * list)
10228 int len = QT_UINT32 (esds->data);
10229 guint8 *ptr = esds->data;
10230 guint8 *end = ptr + len;
10232 guint8 *data_ptr = NULL;
10234 guint8 object_type_id = 0;
10235 const char *codec_name = NULL;
10236 GstCaps *caps = NULL;
10238 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
10240 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
10242 while (ptr + 1 < end) {
10243 tag = QT_UINT8 (ptr);
10244 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
10246 len = read_descr_size (ptr, end, &ptr);
10247 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
10249 /* Check the stated amount of data is available for reading */
10250 if (len < 0 || ptr + len > end)
10254 case ES_DESCRIPTOR_TAG:
10255 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
10256 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
10259 case DECODER_CONFIG_DESC_TAG:{
10260 guint max_bitrate, avg_bitrate;
10262 object_type_id = QT_UINT8 (ptr);
10263 max_bitrate = QT_UINT32 (ptr + 5);
10264 avg_bitrate = QT_UINT32 (ptr + 9);
10265 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
10266 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
10267 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
10268 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
10269 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
10270 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
10271 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
10272 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
10274 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
10275 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
10276 avg_bitrate, NULL);
10281 case DECODER_SPECIFIC_INFO_TAG:
10282 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
10283 if (object_type_id == 0xe0 && len == 0x40) {
10289 GST_DEBUG_OBJECT (qtdemux,
10290 "Have VOBSUB palette. Creating palette event");
10291 /* move to decConfigDescr data and read palette */
10293 for (i = 0; i < 16; i++) {
10294 clut[i] = QT_UINT32 (data);
10298 s = gst_structure_new ("application/x-gst-dvd", "event",
10299 G_TYPE_STRING, "dvd-spu-clut-change",
10300 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
10301 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
10302 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
10303 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
10304 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
10305 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
10306 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
10307 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
10310 /* store event and trigger custom processing */
10311 stream->pending_event =
10312 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
10314 /* Generic codec_data handler puts it on the caps */
10321 case SL_CONFIG_DESC_TAG:
10322 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
10326 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
10328 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
10334 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
10335 * in use, and should also be used to override some other parameters for some
10337 switch (object_type_id) {
10338 case 0x20: /* MPEG-4 */
10339 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
10340 * profile_and_level_indication */
10341 if (data_ptr != NULL && data_len >= 5 &&
10342 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
10343 gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
10344 data_ptr + 4, data_len - 4);
10346 break; /* Nothing special needed here */
10347 case 0x21: /* H.264 */
10348 codec_name = "H.264 / AVC";
10349 caps = gst_caps_new_simple ("video/x-h264",
10350 "stream-format", G_TYPE_STRING, "avc",
10351 "alignment", G_TYPE_STRING, "au", NULL);
10353 case 0x40: /* AAC (any) */
10354 case 0x66: /* AAC Main */
10355 case 0x67: /* AAC LC */
10356 case 0x68: /* AAC SSR */
10357 /* Override channels and rate based on the codec_data, as it's often
10359 /* Only do so for basic setup without HE-AAC extension */
10360 if (data_ptr && data_len == 2) {
10361 guint channels, rateindex, rate;
10363 /* FIXME: add gst_codec_utils_aac_get_{channels|sample_rate}()? */
10364 channels = (data_ptr[1] & 0x7f) >> 3;
10365 if (channels > 0 && channels < 7) {
10366 stream->n_channels = channels;
10367 } else if (channels == 7) {
10368 stream->n_channels = 8;
10371 rateindex = ((data_ptr[0] & 0x7) << 1) | ((data_ptr[1] & 0x80) >> 7);
10372 rate = gst_codec_utils_aac_get_sample_rate_from_index (rateindex);
10374 stream->rate = rate;
10377 /* Set level and profile if possible */
10378 if (data_ptr != NULL && data_len >= 2) {
10379 gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
10380 data_ptr, data_len);
10383 case 0x60: /* MPEG-2, various profiles */
10389 codec_name = "MPEG-2 video";
10390 caps = gst_caps_new_simple ("video/mpeg",
10391 "mpegversion", G_TYPE_INT, 2,
10392 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
10394 case 0x69: /* MPEG-2 BC audio */
10395 case 0x6B: /* MPEG-1 audio */
10396 caps = gst_caps_new_simple ("audio/mpeg",
10397 "mpegversion", G_TYPE_INT, 1, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
10398 codec_name = "MPEG-1 audio";
10400 case 0x6A: /* MPEG-1 */
10401 codec_name = "MPEG-1 video";
10402 caps = gst_caps_new_simple ("video/mpeg",
10403 "mpegversion", G_TYPE_INT, 1,
10404 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
10406 case 0x6C: /* MJPEG */
10407 caps = gst_caps_new_empty_simple ("image/jpeg");
10408 codec_name = "Motion-JPEG";
10410 case 0x6D: /* PNG */
10411 caps = gst_caps_new_empty_simple ("image/png");
10412 codec_name = "PNG still images";
10414 case 0x6E: /* JPEG2000 */
10415 codec_name = "JPEG-2000";
10416 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
10418 case 0xA4: /* Dirac */
10419 codec_name = "Dirac";
10420 caps = gst_caps_new_empty_simple ("video/x-dirac");
10422 case 0xA5: /* AC3 */
10423 codec_name = "AC-3 audio";
10424 caps = gst_caps_new_simple ("audio/x-ac3",
10425 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
10427 case 0xE1: /* QCELP */
10428 /* QCELP, the codec_data is a riff tag (little endian) with
10429 * 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). */
10430 caps = gst_caps_new_empty_simple ("audio/qcelp");
10431 codec_name = "QCELP";
10437 /* If we have a replacement caps, then change our caps for this stream */
10439 gst_caps_unref (stream->caps);
10440 stream->caps = caps;
10443 if (codec_name && list)
10444 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
10445 GST_TAG_AUDIO_CODEC, codec_name, NULL);
10447 /* Add the codec_data attribute to caps, if we have it */
10451 buffer = gst_buffer_new_and_alloc (data_len);
10452 gst_buffer_fill (buffer, 0, data_ptr, data_len);
10454 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
10455 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
10457 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
10459 gst_buffer_unref (buffer);
10464 #define _codec(name) \
10466 if (codec_name) { \
10467 *codec_name = g_strdup (name); \
10472 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
10473 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
10475 GstCaps *caps = NULL;
10476 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
10479 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
10480 _codec ("PNG still images");
10481 caps = gst_caps_new_empty_simple ("image/png");
10483 case GST_MAKE_FOURCC ('j', 'p', 'e', 'g'):
10484 _codec ("JPEG still images");
10485 caps = gst_caps_new_empty_simple ("image/jpeg");
10487 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
10488 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
10489 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
10490 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
10491 _codec ("Motion-JPEG");
10492 caps = gst_caps_new_empty_simple ("image/jpeg");
10494 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
10495 _codec ("Motion-JPEG format B");
10496 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
10498 case GST_MAKE_FOURCC ('m', 'j', 'p', '2'):
10499 _codec ("JPEG-2000");
10500 /* override to what it should be according to spec, avoid palette_data */
10501 stream->bits_per_sample = 24;
10502 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
10504 case GST_MAKE_FOURCC ('S', 'V', 'Q', '3'):
10505 _codec ("Sorensen video v.3");
10506 caps = gst_caps_new_simple ("video/x-svq",
10507 "svqversion", G_TYPE_INT, 3, NULL);
10509 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
10510 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
10511 _codec ("Sorensen video v.1");
10512 caps = gst_caps_new_simple ("video/x-svq",
10513 "svqversion", G_TYPE_INT, 1, NULL);
10515 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
10516 caps = gst_caps_new_empty_simple ("video/x-raw");
10517 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
10518 _codec ("Windows Raw RGB");
10520 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
10524 bps = QT_UINT16 (stsd_data + 98);
10527 format = GST_VIDEO_FORMAT_RGB15;
10530 format = GST_VIDEO_FORMAT_RGB16;
10533 format = GST_VIDEO_FORMAT_RGB;
10536 format = GST_VIDEO_FORMAT_ARGB;
10544 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
10545 format = GST_VIDEO_FORMAT_I420;
10547 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
10548 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
10549 format = GST_VIDEO_FORMAT_I420;
10551 case GST_MAKE_FOURCC ('2', 'v', 'u', 'y'):
10552 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
10553 case GST_MAKE_FOURCC ('v', '2', '1', '0'):
10554 format = GST_VIDEO_FORMAT_UYVY;
10556 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
10557 format = GST_VIDEO_FORMAT_r210;
10559 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
10560 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
10561 _codec ("MPEG-1 video");
10562 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
10563 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
10565 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
10566 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
10567 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
10568 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
10569 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
10570 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
10571 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
10572 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
10573 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
10574 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
10575 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
10576 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
10577 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
10578 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
10579 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
10580 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
10581 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
10582 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
10583 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
10584 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
10585 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
10586 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
10587 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
10588 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
10589 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
10590 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
10591 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
10592 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
10593 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
10594 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
10595 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
10596 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
10597 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
10598 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
10599 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
10600 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
10601 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
10602 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
10603 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
10604 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
10605 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
10606 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
10607 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
10608 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
10609 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
10610 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
10611 _codec ("MPEG-2 video");
10612 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
10613 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
10615 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
10616 _codec ("GIF still images");
10617 caps = gst_caps_new_empty_simple ("image/gif");
10619 case GST_MAKE_FOURCC ('h', '2', '6', '3'):
10620 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
10621 case GST_MAKE_FOURCC ('s', '2', '6', '3'):
10622 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
10624 /* ffmpeg uses the height/width props, don't know why */
10625 caps = gst_caps_new_simple ("video/x-h263",
10626 "variant", G_TYPE_STRING, "itu", NULL);
10628 case GST_MAKE_FOURCC ('m', 'p', '4', 'v'):
10629 case GST_MAKE_FOURCC ('M', 'P', '4', 'V'):
10630 _codec ("MPEG-4 video");
10631 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
10632 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
10634 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
10635 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
10636 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
10637 caps = gst_caps_new_simple ("video/x-msmpeg",
10638 "msmpegversion", G_TYPE_INT, 43, NULL);
10640 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
10642 caps = gst_caps_new_simple ("video/x-divx",
10643 "divxversion", G_TYPE_INT, 3, NULL);
10645 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
10646 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
10648 caps = gst_caps_new_simple ("video/x-divx",
10649 "divxversion", G_TYPE_INT, 4, NULL);
10651 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
10653 caps = gst_caps_new_simple ("video/x-divx",
10654 "divxversion", G_TYPE_INT, 5, NULL);
10657 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
10658 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
10659 case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
10660 case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
10661 case GST_MAKE_FOURCC ('F', 'M', 'P', '4'):
10662 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
10663 caps = gst_caps_new_simple ("video/mpeg",
10664 "mpegversion", G_TYPE_INT, 4, NULL);
10666 *codec_name = g_strdup ("MPEG-4");
10669 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
10670 _codec ("Cinepak");
10671 caps = gst_caps_new_empty_simple ("video/x-cinepak");
10673 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
10674 _codec ("Apple QuickDraw");
10675 caps = gst_caps_new_empty_simple ("video/x-qdrw");
10677 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
10678 _codec ("Apple video");
10679 caps = gst_caps_new_empty_simple ("video/x-apple-video");
10681 case GST_MAKE_FOURCC ('H', '2', '6', '4'):
10682 case GST_MAKE_FOURCC ('a', 'v', 'c', '1'):
10683 _codec ("H.264 / AVC");
10684 caps = gst_caps_new_simple ("video/x-h264",
10685 "stream-format", G_TYPE_STRING, "avc",
10686 "alignment", G_TYPE_STRING, "au", NULL);
10688 case GST_MAKE_FOURCC ('a', 'v', 'c', '3'):
10689 _codec ("H.264 / AVC");
10690 caps = gst_caps_new_simple ("video/x-h264",
10691 "stream-format", G_TYPE_STRING, "avc3",
10692 "alignment", G_TYPE_STRING, "au", NULL);
10694 case GST_MAKE_FOURCC ('H', '2', '6', '5'):
10695 case GST_MAKE_FOURCC ('h', 'v', 'c', '1'):
10696 _codec ("H.265 / HEVC");
10697 caps = gst_caps_new_simple ("video/x-h265",
10698 "stream-format", G_TYPE_STRING, "hvc1",
10699 "alignment", G_TYPE_STRING, "au", NULL);
10701 case GST_MAKE_FOURCC ('h', 'e', 'v', '1'):
10702 _codec ("H.265 / HEVC");
10703 caps = gst_caps_new_simple ("video/x-h265",
10704 "stream-format", G_TYPE_STRING, "hev1",
10705 "alignment", G_TYPE_STRING, "au", NULL);
10707 case GST_MAKE_FOURCC ('r', 'l', 'e', ' '):
10708 _codec ("Run-length encoding");
10709 caps = gst_caps_new_simple ("video/x-rle",
10710 "layout", G_TYPE_STRING, "quicktime", NULL);
10712 case GST_MAKE_FOURCC ('W', 'R', 'L', 'E'):
10713 _codec ("Run-length encoding");
10714 caps = gst_caps_new_simple ("video/x-rle",
10715 "layout", G_TYPE_STRING, "microsoft", NULL);
10717 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
10718 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
10719 _codec ("Indeo Video 3");
10720 caps = gst_caps_new_simple ("video/x-indeo",
10721 "indeoversion", G_TYPE_INT, 3, NULL);
10723 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
10724 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
10725 _codec ("Intel Video 4");
10726 caps = gst_caps_new_simple ("video/x-indeo",
10727 "indeoversion", G_TYPE_INT, 4, NULL);
10729 case GST_MAKE_FOURCC ('d', 'v', 'c', 'p'):
10730 case GST_MAKE_FOURCC ('d', 'v', 'c', ' '):
10731 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
10732 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
10733 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
10734 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
10735 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
10736 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
10737 _codec ("DV Video");
10738 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
10739 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
10741 case GST_MAKE_FOURCC ('d', 'v', '5', 'n'): /* DVCPRO50 NTSC */
10742 case GST_MAKE_FOURCC ('d', 'v', '5', 'p'): /* DVCPRO50 PAL */
10743 _codec ("DVCPro50 Video");
10744 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
10745 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
10747 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
10748 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
10749 _codec ("DVCProHD Video");
10750 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
10751 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
10753 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
10754 _codec ("Apple Graphics (SMC)");
10755 caps = gst_caps_new_empty_simple ("video/x-smc");
10757 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
10759 caps = gst_caps_new_empty_simple ("video/x-vp3");
10761 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
10762 _codec ("VP6 Flash");
10763 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
10765 case GST_MAKE_FOURCC ('X', 'i', 'T', 'h'):
10767 caps = gst_caps_new_empty_simple ("video/x-theora");
10768 /* theora uses one byte of padding in the data stream because it does not
10769 * allow 0 sized packets while theora does */
10770 stream->padding = 1;
10772 case GST_MAKE_FOURCC ('d', 'r', 'a', 'c'):
10774 caps = gst_caps_new_empty_simple ("video/x-dirac");
10776 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
10777 _codec ("TIFF still images");
10778 caps = gst_caps_new_empty_simple ("image/tiff");
10780 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
10781 _codec ("Apple Intermediate Codec");
10782 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
10784 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
10785 _codec ("AVID DNxHD");
10786 caps = gst_caps_from_string ("video/x-dnxhd");
10788 case GST_MAKE_FOURCC ('V', 'P', '8', '0'):
10789 _codec ("On2 VP8");
10790 caps = gst_caps_from_string ("video/x-vp8");
10792 case GST_MAKE_FOURCC ('a', 'p', 'c', 's'):
10793 _codec ("Apple ProRes LT");
10795 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
10798 case GST_MAKE_FOURCC ('a', 'p', 'c', 'h'):
10799 _codec ("Apple ProRes HQ");
10801 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
10804 case GST_MAKE_FOURCC ('a', 'p', 'c', 'n'):
10805 _codec ("Apple ProRes");
10807 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
10810 case GST_MAKE_FOURCC ('a', 'p', 'c', 'o'):
10811 _codec ("Apple ProRes Proxy");
10813 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
10816 case GST_MAKE_FOURCC ('a', 'p', '4', 'h'):
10817 _codec ("Apple ProRes 4444");
10819 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
10824 caps = gst_caps_new_simple ("video/x-wmv",
10825 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
10827 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
10830 char *s, fourstr[5];
10832 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
10833 s = g_strdup_printf ("video/x-gst-fourcc-%s", g_strstrip (fourstr));
10834 caps = gst_caps_new_empty_simple (s);
10839 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
10842 gst_video_info_init (&info);
10843 gst_video_info_set_format (&info, format, stream->width, stream->height);
10844 caps = gst_video_info_to_caps (&info);
10845 *codec_name = gst_pb_utils_get_codec_description (caps);
10847 /* enable clipping for raw video streams */
10848 stream->need_clip = TRUE;
10855 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
10856 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
10859 const GstStructure *s;
10863 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
10866 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
10867 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
10868 _codec ("Raw 8-bit PCM audio");
10869 caps = gst_caps_new_simple ("audio/x-raw",
10870 "format", G_TYPE_STRING, "U8",
10871 "layout", G_TYPE_STRING, "interleaved", NULL);
10873 case GST_MAKE_FOURCC ('t', 'w', 'o', 's'):
10874 endian = G_BIG_ENDIAN;
10876 case GST_MAKE_FOURCC ('s', 'o', 'w', 't'):
10880 GstAudioFormat format;
10883 endian = G_LITTLE_ENDIAN;
10885 depth = stream->bytes_per_packet * 8;
10886 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
10888 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
10892 caps = gst_caps_new_simple ("audio/x-raw",
10893 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
10894 "layout", G_TYPE_STRING, "interleaved", NULL);
10897 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
10898 _codec ("Raw 64-bit floating-point audio");
10899 caps = gst_caps_new_simple ("audio/x-raw",
10900 "format", G_TYPE_STRING, "F64BE",
10901 "layout", G_TYPE_STRING, "interleaved", NULL);
10903 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
10904 _codec ("Raw 32-bit floating-point audio");
10905 caps = gst_caps_new_simple ("audio/x-raw",
10906 "format", G_TYPE_STRING, "F32BE",
10907 "layout", G_TYPE_STRING, "interleaved", NULL);
10910 _codec ("Raw 24-bit PCM audio");
10911 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
10913 caps = gst_caps_new_simple ("audio/x-raw",
10914 "format", G_TYPE_STRING, "S24BE",
10915 "layout", G_TYPE_STRING, "interleaved", NULL);
10917 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
10918 _codec ("Raw 32-bit PCM audio");
10919 caps = gst_caps_new_simple ("audio/x-raw",
10920 "format", G_TYPE_STRING, "S32BE",
10921 "layout", G_TYPE_STRING, "interleaved", NULL);
10923 case GST_MAKE_FOURCC ('u', 'l', 'a', 'w'):
10924 _codec ("Mu-law audio");
10925 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
10927 case GST_MAKE_FOURCC ('a', 'l', 'a', 'w'):
10928 _codec ("A-law audio");
10929 caps = gst_caps_new_empty_simple ("audio/x-alaw");
10933 _codec ("Microsoft ADPCM");
10934 /* Microsoft ADPCM-ACM code 2 */
10935 caps = gst_caps_new_simple ("audio/x-adpcm",
10936 "layout", G_TYPE_STRING, "microsoft", NULL);
10940 _codec ("DVI/IMA ADPCM");
10941 caps = gst_caps_new_simple ("audio/x-adpcm",
10942 "layout", G_TYPE_STRING, "dvi", NULL);
10946 _codec ("DVI/Intel IMA ADPCM");
10947 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
10948 caps = gst_caps_new_simple ("audio/x-adpcm",
10949 "layout", G_TYPE_STRING, "quicktime", NULL);
10953 /* MPEG layer 3, CBR only (pre QT4.1) */
10954 case GST_MAKE_FOURCC ('.', 'm', 'p', '3'):
10955 _codec ("MPEG-1 layer 3");
10956 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
10957 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
10958 "mpegversion", G_TYPE_INT, 1, NULL);
10961 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
10962 _codec ("EAC-3 audio");
10963 caps = gst_caps_new_simple ("audio/x-eac3",
10964 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
10965 stream->sampled = TRUE;
10967 case GST_MAKE_FOURCC ('a', 'c', '-', '3'):
10968 _codec ("AC-3 audio");
10969 caps = gst_caps_new_simple ("audio/x-ac3",
10970 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
10971 stream->sampled = TRUE;
10973 case GST_MAKE_FOURCC ('M', 'A', 'C', '3'):
10975 caps = gst_caps_new_simple ("audio/x-mace",
10976 "maceversion", G_TYPE_INT, 3, NULL);
10978 case GST_MAKE_FOURCC ('M', 'A', 'C', '6'):
10980 caps = gst_caps_new_simple ("audio/x-mace",
10981 "maceversion", G_TYPE_INT, 6, NULL);
10983 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
10985 caps = gst_caps_new_empty_simple ("application/ogg");
10987 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
10988 _codec ("DV audio");
10989 caps = gst_caps_new_empty_simple ("audio/x-dv");
10991 case GST_MAKE_FOURCC ('m', 'p', '4', 'a'):
10992 _codec ("MPEG-4 AAC audio");
10993 caps = gst_caps_new_simple ("audio/mpeg",
10994 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
10995 "stream-format", G_TYPE_STRING, "raw", NULL);
10997 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
10998 _codec ("QDesign Music");
10999 caps = gst_caps_new_empty_simple ("audio/x-qdm");
11001 case GST_MAKE_FOURCC ('Q', 'D', 'M', '2'):
11002 _codec ("QDesign Music v.2");
11003 /* FIXME: QDesign music version 2 (no constant) */
11004 if (FALSE && data) {
11005 caps = gst_caps_new_simple ("audio/x-qdm2",
11006 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
11007 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
11008 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
11010 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
11013 case GST_MAKE_FOURCC ('a', 'g', 's', 'm'):
11014 _codec ("GSM audio");
11015 caps = gst_caps_new_empty_simple ("audio/x-gsm");
11017 case GST_MAKE_FOURCC ('s', 'a', 'm', 'r'):
11018 _codec ("AMR audio");
11019 caps = gst_caps_new_empty_simple ("audio/AMR");
11021 case GST_MAKE_FOURCC ('s', 'a', 'w', 'b'):
11022 _codec ("AMR-WB audio");
11023 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
11025 case GST_MAKE_FOURCC ('i', 'm', 'a', '4'):
11026 _codec ("Quicktime IMA ADPCM");
11027 caps = gst_caps_new_simple ("audio/x-adpcm",
11028 "layout", G_TYPE_STRING, "quicktime", NULL);
11030 case GST_MAKE_FOURCC ('a', 'l', 'a', 'c'):
11031 _codec ("Apple lossless audio");
11032 caps = gst_caps_new_empty_simple ("audio/x-alac");
11034 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
11035 _codec ("QualComm PureVoice");
11036 caps = gst_caps_from_string ("audio/qcelp");
11040 caps = gst_caps_new_empty_simple ("audio/x-wma");
11042 case GST_MAKE_FOURCC ('l', 'p', 'c', 'm'):
11047 GstAudioFormat format;
11050 FLAG_IS_FLOAT = 0x1,
11051 FLAG_IS_BIG_ENDIAN = 0x2,
11052 FLAG_IS_SIGNED = 0x4,
11053 FLAG_IS_PACKED = 0x8,
11054 FLAG_IS_ALIGNED_HIGH = 0x10,
11055 FLAG_IS_NON_INTERLEAVED = 0x20
11057 _codec ("Raw LPCM audio");
11059 if (data && len >= 56) {
11060 depth = QT_UINT32 (data + 40);
11061 flags = QT_UINT32 (data + 44);
11062 width = QT_UINT32 (data + 48) * 8 / stream->n_channels;
11064 if ((flags & FLAG_IS_FLOAT) == 0) {
11069 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
11070 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
11071 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
11072 caps = gst_caps_new_simple ("audio/x-raw",
11073 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
11074 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
11075 "non-interleaved" : "interleaved", NULL);
11082 if (flags & FLAG_IS_BIG_ENDIAN)
11083 format = GST_AUDIO_FORMAT_F64BE;
11085 format = GST_AUDIO_FORMAT_F64LE;
11087 if (flags & FLAG_IS_BIG_ENDIAN)
11088 format = GST_AUDIO_FORMAT_F32BE;
11090 format = GST_AUDIO_FORMAT_F32LE;
11092 caps = gst_caps_new_simple ("audio/x-raw",
11093 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
11094 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
11095 "non-interleaved" : "interleaved", NULL);
11099 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
11103 char *s, fourstr[5];
11105 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11106 s = g_strdup_printf ("audio/x-gst-fourcc-%s", g_strstrip (fourstr));
11107 caps = gst_caps_new_empty_simple (s);
11113 GstCaps *templ_caps =
11114 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
11115 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
11116 gst_caps_unref (caps);
11117 gst_caps_unref (templ_caps);
11118 caps = intersection;
11121 /* enable clipping for raw audio streams */
11122 s = gst_caps_get_structure (caps, 0);
11123 name = gst_structure_get_name (s);
11124 if (g_str_has_prefix (name, "audio/x-raw")) {
11125 stream->need_clip = TRUE;
11126 stream->max_buffer_size = 4096 * stream->bytes_per_frame;
11127 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
11133 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
11134 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
11138 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
11141 case GST_MAKE_FOURCC ('m', 'p', '4', 's'):
11142 _codec ("DVD subtitle");
11143 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
11144 stream->need_process = TRUE;
11146 case GST_MAKE_FOURCC ('t', 'e', 'x', 't'):
11147 _codec ("Quicktime timed text");
11149 case GST_MAKE_FOURCC ('t', 'x', '3', 'g'):
11150 _codec ("3GPP timed text");
11152 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
11154 /* actual text piece needs to be extracted */
11155 stream->need_process = TRUE;
11159 char *s, fourstr[5];
11161 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11162 s = g_strdup_printf ("text/x-gst-fourcc-%s", g_strstrip (fourstr));
11163 caps = gst_caps_new_empty_simple (s);
11171 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
11172 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
11177 case GST_MAKE_FOURCC ('m', '1', 'v', ' '):
11178 _codec ("MPEG 1 video");
11179 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
11180 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);