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 goto unknown_stream;
7497 list = gst_tag_list_new_empty ();
7498 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7499 GST_TAG_VIDEO_CODEC, codec, NULL);
7508 if (stream->rgb8_palette)
7509 gst_memory_unref (stream->rgb8_palette);
7510 stream->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
7511 palette_data, palette_size, 0, palette_size, palette_data, g_free);
7513 s = gst_caps_get_structure (stream->caps, 0);
7515 /* non-raw video has a palette_data property. raw video has the palette as
7516 * an extra plane that we append to the output buffers before we push
7518 if (!gst_structure_has_name (s, "video/x-raw")) {
7521 palette = gst_buffer_new ();
7522 gst_buffer_append_memory (palette, stream->rgb8_palette);
7523 stream->rgb8_palette = NULL;
7525 gst_caps_set_simple (stream->caps, "palette_data",
7526 GST_TYPE_BUFFER, palette, NULL);
7527 gst_buffer_unref (palette);
7529 } else if (palette_count != 0) {
7530 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
7531 (NULL), ("Unsupported palette depth %d", depth));
7534 GST_LOG_OBJECT (qtdemux, "frame count: %u",
7535 QT_UINT16 (stsd_data + offset + 48));
7539 /* pick 'the' stsd child */
7540 mp4v = qtdemux_tree_get_child_by_type (stsd, fourcc);
7542 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
7543 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
7547 const guint8 *pasp_data = (const guint8 *) pasp->data;
7549 stream->par_w = QT_UINT32 (pasp_data + 8);
7550 stream->par_h = QT_UINT32 (pasp_data + 12);
7557 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
7564 gint len = QT_UINT32 (stsd_data) - 0x66;
7565 const guint8 *avc_data = stsd_data + 0x66;
7568 while (len >= 0x8) {
7571 if (QT_UINT32 (avc_data) <= len)
7572 size = QT_UINT32 (avc_data) - 0x8;
7577 /* No real data, so break out */
7580 switch (QT_FOURCC (avc_data + 0x4)) {
7583 /* parse, if found */
7586 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
7588 /* First 4 bytes are the length of the atom, the next 4 bytes
7589 * are the fourcc, the next 1 byte is the version, and the
7590 * subsequent bytes are profile_tier_level structure like data. */
7591 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
7592 avc_data + 8 + 1, size - 1);
7593 buf = gst_buffer_new_and_alloc (size);
7594 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
7595 gst_caps_set_simple (stream->caps,
7596 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7597 gst_buffer_unref (buf);
7605 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
7607 /* First 4 bytes are the length of the atom, the next 4 bytes
7608 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
7609 * next 1 byte is the version, and the
7610 * subsequent bytes are sequence parameter set like data. */
7612 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
7614 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
7615 avc_data + 8 + 40 + 1, size - 1);
7617 buf = gst_buffer_new_and_alloc (size);
7618 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
7619 gst_caps_set_simple (stream->caps,
7620 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7621 gst_buffer_unref (buf);
7627 guint avg_bitrate, max_bitrate;
7629 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
7633 max_bitrate = QT_UINT32 (avc_data + 0xc);
7634 avg_bitrate = QT_UINT32 (avc_data + 0x10);
7636 if (!max_bitrate && !avg_bitrate)
7639 /* Some muxers seem to swap the average and maximum bitrates
7640 * (I'm looking at you, YouTube), so we swap for sanity. */
7641 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
7642 guint temp = avg_bitrate;
7644 avg_bitrate = max_bitrate;
7649 list = gst_tag_list_new_empty ();
7651 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
7652 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7653 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
7655 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
7656 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7657 GST_TAG_BITRATE, avg_bitrate, NULL);
7668 avc_data += size + 8;
7677 gint len = QT_UINT32 (stsd_data) - 0x66;
7678 const guint8 *hevc_data = stsd_data + 0x66;
7681 while (len >= 0x8) {
7684 if (QT_UINT32 (hevc_data) <= len)
7685 size = QT_UINT32 (hevc_data) - 0x8;
7690 /* No real data, so break out */
7693 switch (QT_FOURCC (hevc_data + 0x4)) {
7696 /* parse, if found */
7699 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
7701 /* First 4 bytes are the length of the atom, the next 4 bytes
7702 * are the fourcc, the next 1 byte is the version, and the
7703 * subsequent bytes are sequence parameter set like data. */
7704 gst_codec_utils_h265_caps_set_level_tier_and_profile
7705 (stream->caps, hevc_data + 8 + 1, size - 1);
7707 buf = gst_buffer_new_and_alloc (size);
7708 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
7709 gst_caps_set_simple (stream->caps,
7710 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7711 gst_buffer_unref (buf);
7718 hevc_data += size + 8;
7729 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
7730 GST_FOURCC_ARGS (fourcc));
7732 /* codec data might be in glbl extension atom */
7734 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
7740 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
7742 len = QT_UINT32 (data);
7745 buf = gst_buffer_new_and_alloc (len);
7746 gst_buffer_fill (buf, 0, data + 8, len);
7747 gst_caps_set_simple (stream->caps,
7748 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7749 gst_buffer_unref (buf);
7756 /* see annex I of the jpeg2000 spec */
7757 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
7759 const gchar *colorspace = NULL;
7761 guint32 ncomp_map = 0;
7762 gint32 *comp_map = NULL;
7763 guint32 nchan_def = 0;
7764 gint32 *chan_def = NULL;
7766 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
7767 /* some required atoms */
7768 mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
7771 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
7775 /* number of components; redundant with info in codestream, but useful
7777 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
7778 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
7780 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
7782 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
7785 GST_DEBUG_OBJECT (qtdemux, "found colr");
7786 /* extract colour space info */
7787 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
7788 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
7790 colorspace = "sRGB";
7793 colorspace = "GRAY";
7796 colorspace = "sYUV";
7804 /* colr is required, and only values 16, 17, and 18 are specified,
7805 so error if we have no colorspace */
7808 /* extract component mapping */
7809 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
7811 guint32 cmap_len = 0;
7813 cmap_len = QT_UINT32 (cmap->data);
7814 if (cmap_len >= 8) {
7815 /* normal box, subtract off header */
7817 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
7818 if (cmap_len % 4 == 0) {
7819 ncomp_map = (cmap_len / 4);
7820 comp_map = g_new0 (gint32, ncomp_map);
7821 for (i = 0; i < ncomp_map; i++) {
7824 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
7825 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
7826 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
7827 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
7832 /* extract channel definitions */
7833 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
7835 guint32 cdef_len = 0;
7837 cdef_len = QT_UINT32 (cdef->data);
7838 if (cdef_len >= 10) {
7839 /* normal box, subtract off header and len */
7841 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
7842 if (cdef_len % 6 == 0) {
7843 nchan_def = (cdef_len / 6);
7844 chan_def = g_new0 (gint32, nchan_def);
7845 for (i = 0; i < nchan_def; i++)
7847 for (i = 0; i < nchan_def; i++) {
7848 guint16 cn, typ, asoc;
7849 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
7850 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
7851 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
7852 if (cn < nchan_def) {
7855 chan_def[cn] = asoc;
7858 chan_def[cn] = 0; /* alpha */
7861 chan_def[cn] = -typ;
7869 gst_caps_set_simple (stream->caps,
7870 "num-components", G_TYPE_INT, ncomp, NULL);
7871 gst_caps_set_simple (stream->caps,
7872 "colorspace", G_TYPE_STRING, colorspace, NULL);
7875 GValue arr = { 0, };
7876 GValue elt = { 0, };
7878 g_value_init (&arr, GST_TYPE_ARRAY);
7879 g_value_init (&elt, G_TYPE_INT);
7880 for (i = 0; i < ncomp_map; i++) {
7881 g_value_set_int (&elt, comp_map[i]);
7882 gst_value_array_append_value (&arr, &elt);
7884 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
7885 "component-map", &arr);
7886 g_value_unset (&elt);
7887 g_value_unset (&arr);
7892 GValue arr = { 0, };
7893 GValue elt = { 0, };
7895 g_value_init (&arr, GST_TYPE_ARRAY);
7896 g_value_init (&elt, G_TYPE_INT);
7897 for (i = 0; i < nchan_def; i++) {
7898 g_value_set_int (&elt, chan_def[i]);
7899 gst_value_array_append_value (&arr, &elt);
7901 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
7902 "channel-definitions", &arr);
7903 g_value_unset (&elt);
7904 g_value_unset (&arr);
7908 /* some optional atoms */
7909 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
7910 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
7912 /* indicate possible fields in caps */
7914 data = (guint8 *) field->data + 8;
7916 gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
7917 (gint) * data, NULL);
7919 /* add codec_data if provided */
7924 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
7925 data = prefix->data;
7926 len = QT_UINT32 (data);
7929 buf = gst_buffer_new_and_alloc (len);
7930 gst_buffer_fill (buf, 0, data + 8, len);
7931 gst_caps_set_simple (stream->caps,
7932 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7933 gst_buffer_unref (buf);
7942 GstBuffer *seqh = NULL;
7943 guint8 *gamma_data = NULL;
7944 gint len = QT_UINT32 (stsd_data);
7946 qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
7948 gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
7949 QT_FP32 (gamma_data), NULL);
7952 /* sorry for the bad name, but we don't know what this is, other
7953 * than its own fourcc */
7954 gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
7958 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
7959 buf = gst_buffer_new_and_alloc (len);
7960 gst_buffer_fill (buf, 0, stsd_data, len);
7961 gst_caps_set_simple (stream->caps,
7962 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7963 gst_buffer_unref (buf);
7969 gst_caps_set_simple (stream->caps,
7970 "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
7977 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
7978 xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
7982 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
7986 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
7987 /* collect the headers and store them in a stream list so that we can
7988 * send them out first */
7989 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
7999 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
8000 ovc1 = qtdemux_tree_get_child_by_type (stsd, FOURCC_ovc1);
8003 ovc1_data = ovc1->data;
8004 ovc1_len = QT_UINT32 (ovc1_data);
8005 if (ovc1_len <= 198) {
8006 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
8009 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
8010 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
8011 gst_caps_set_simple (stream->caps,
8012 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8013 gst_buffer_unref (buf);
8021 GST_INFO_OBJECT (qtdemux,
8022 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
8023 GST_FOURCC_ARGS (fourcc), stream->caps);
8025 } else if (stream->subtype == FOURCC_soun) {
8026 int version, samplesize;
8027 guint16 compression_id;
8028 gboolean amrwb = FALSE;
8031 /* sample description entry (16) + sound sample description v0 (20) */
8035 version = QT_UINT32 (stsd_data + offset);
8036 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
8037 samplesize = QT_UINT16 (stsd_data + offset + 10);
8038 compression_id = QT_UINT16 (stsd_data + offset + 12);
8039 stream->rate = QT_FP32 (stsd_data + offset + 16);
8041 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
8042 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
8043 QT_UINT32 (stsd_data + offset + 4));
8044 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
8045 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
8046 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
8047 GST_LOG_OBJECT (qtdemux, "packet size: %d",
8048 QT_UINT16 (stsd_data + offset + 14));
8049 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
8051 if (compression_id == 0xfffe)
8052 stream->sampled = TRUE;
8054 /* first assume uncompressed audio */
8055 stream->bytes_per_sample = samplesize / 8;
8056 stream->samples_per_frame = stream->n_channels;
8057 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
8058 stream->samples_per_packet = stream->samples_per_frame;
8059 stream->bytes_per_packet = stream->bytes_per_sample;
8063 /* Yes, these have to be hard-coded */
8066 stream->samples_per_packet = 6;
8067 stream->bytes_per_packet = 1;
8068 stream->bytes_per_frame = 1 * stream->n_channels;
8069 stream->bytes_per_sample = 1;
8070 stream->samples_per_frame = 6 * stream->n_channels;
8075 stream->samples_per_packet = 3;
8076 stream->bytes_per_packet = 1;
8077 stream->bytes_per_frame = 1 * stream->n_channels;
8078 stream->bytes_per_sample = 1;
8079 stream->samples_per_frame = 3 * stream->n_channels;
8084 stream->samples_per_packet = 64;
8085 stream->bytes_per_packet = 34;
8086 stream->bytes_per_frame = 34 * stream->n_channels;
8087 stream->bytes_per_sample = 2;
8088 stream->samples_per_frame = 64 * stream->n_channels;
8094 stream->samples_per_packet = 1;
8095 stream->bytes_per_packet = 1;
8096 stream->bytes_per_frame = 1 * stream->n_channels;
8097 stream->bytes_per_sample = 1;
8098 stream->samples_per_frame = 1 * stream->n_channels;
8103 stream->samples_per_packet = 160;
8104 stream->bytes_per_packet = 33;
8105 stream->bytes_per_frame = 33 * stream->n_channels;
8106 stream->bytes_per_sample = 2;
8107 stream->samples_per_frame = 160 * stream->n_channels;
8114 if (version == 0x00010000) {
8115 /* sample description entry (16) + sound sample description v1 (20+16) */
8126 /* only parse extra decoding config for non-pcm audio */
8127 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
8128 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
8129 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
8130 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
8132 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
8133 stream->samples_per_packet);
8134 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
8135 stream->bytes_per_packet);
8136 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
8137 stream->bytes_per_frame);
8138 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
8139 stream->bytes_per_sample);
8141 if (!stream->sampled && stream->bytes_per_packet) {
8142 stream->samples_per_frame = (stream->bytes_per_frame /
8143 stream->bytes_per_packet) * stream->samples_per_packet;
8144 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
8145 stream->samples_per_frame);
8150 } else if (version == 0x00020000) {
8157 /* sample description entry (16) + sound sample description v2 (56) */
8161 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
8162 stream->rate = qtfp.fp;
8163 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
8165 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
8166 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
8167 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
8168 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
8169 QT_UINT32 (stsd_data + offset + 20));
8170 GST_LOG_OBJECT (qtdemux, "format flags: %X",
8171 QT_UINT32 (stsd_data + offset + 24));
8172 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
8173 QT_UINT32 (stsd_data + offset + 28));
8174 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
8175 QT_UINT32 (stsd_data + offset + 32));
8177 GST_WARNING_OBJECT (qtdemux, "unknown version %08x", version);
8180 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc,
8181 stsd_data + 32, len - 16, &codec);
8189 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
8191 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
8193 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
8195 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
8198 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
8199 gst_caps_set_simple (stream->caps,
8200 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE", NULL);
8207 const guint8 *owma_data;
8208 const gchar *codec_name = NULL;
8212 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
8213 /* FIXME this should also be gst_riff_strf_auds,
8214 * but the latter one is actually missing bits-per-sample :( */
8219 gint32 nSamplesPerSec;
8220 gint32 nAvgBytesPerSec;
8222 gint16 wBitsPerSample;
8227 GST_DEBUG_OBJECT (qtdemux, "parse owma");
8228 owma = qtdemux_tree_get_child_by_type (stsd, FOURCC_owma);
8231 owma_data = owma->data;
8232 owma_len = QT_UINT32 (owma_data);
8233 if (owma_len <= 54) {
8234 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
8237 wfex = (WAVEFORMATEX *) (owma_data + 36);
8238 buf = gst_buffer_new_and_alloc (owma_len - 54);
8239 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
8240 if (wfex->wFormatTag == 0x0161) {
8241 codec_name = "Windows Media Audio";
8243 } else if (wfex->wFormatTag == 0x0162) {
8244 codec_name = "Windows Media Audio 9 Pro";
8246 } else if (wfex->wFormatTag == 0x0163) {
8247 codec_name = "Windows Media Audio 9 Lossless";
8248 /* is that correct? gstffmpegcodecmap.c is missing it, but
8249 * fluendo codec seems to support it */
8253 gst_caps_set_simple (stream->caps,
8254 "codec_data", GST_TYPE_BUFFER, buf,
8255 "wmaversion", G_TYPE_INT, version,
8256 "block_align", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->nBlockAlign),
8257 "bitrate", G_TYPE_INT, GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec),
8258 "width", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
8259 "depth", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
8261 gst_buffer_unref (buf);
8265 codec = g_strdup (codec_name);
8277 list = gst_tag_list_new_empty ();
8278 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
8279 GST_TAG_AUDIO_CODEC, codec, NULL);
8283 /* some bitrate info may have ended up in caps */
8284 s = gst_caps_get_structure (stream->caps, 0);
8285 gst_structure_get_int (s, "bitrate", &bitrate);
8287 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
8291 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
8295 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
8297 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
8299 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
8303 /* If the fourcc's bottom 16 bits gives 'sm', then the top
8304 16 bits is a byte-swapped wave-style codec identifier,
8305 and we can find a WAVE header internally to a 'wave' atom here.
8306 This can more clearly be thought of as 'ms' as the top 16 bits, and a
8307 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
8310 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
8311 if (len < offset + 20) {
8312 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
8314 guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
8315 const guint8 *data = stsd_data + offset + 16;
8317 GNode *waveheadernode;
8319 wavenode = g_node_new ((guint8 *) data);
8320 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
8321 const guint8 *waveheader;
8324 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
8325 if (waveheadernode) {
8326 waveheader = (const guint8 *) waveheadernode->data;
8327 headerlen = QT_UINT32 (waveheader);
8329 if (headerlen > 8) {
8330 gst_riff_strf_auds *header = NULL;
8331 GstBuffer *headerbuf;
8337 headerbuf = gst_buffer_new_and_alloc (headerlen);
8338 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
8340 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
8341 headerbuf, &header, &extra)) {
8342 gst_caps_unref (stream->caps);
8343 /* FIXME: Need to do something with the channel reorder map */
8344 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
8345 header, extra, NULL, NULL, NULL);
8348 gst_buffer_unref (extra);
8353 GST_DEBUG ("Didn't find waveheadernode for this codec");
8355 g_node_destroy (wavenode);
8358 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
8362 /* FIXME: what is in the chunk? */
8365 gint len = QT_UINT32 (stsd_data);
8367 /* seems to be always = 116 = 0x74 */
8373 gint len = QT_UINT32 (stsd_data);
8376 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
8378 gst_buffer_fill (buf, 0, stsd_data + 0x4C, len - 0x4C);
8379 gst_caps_set_simple (stream->caps,
8380 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8381 gst_buffer_unref (buf);
8383 gst_caps_set_simple (stream->caps,
8384 "samplesize", G_TYPE_INT, samplesize, NULL);
8389 GNode *alac, *wave = NULL;
8391 /* apparently, m4a has this atom appended directly in the stsd entry,
8392 * while mov has it in a wave atom */
8393 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
8395 /* alac now refers to stsd entry atom */
8396 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
8398 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
8400 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
8403 const guint8 *alac_data = alac->data;
8404 gint len = QT_UINT32 (alac->data);
8408 GST_DEBUG_OBJECT (qtdemux,
8409 "discarding alac atom with unexpected len %d", len);
8411 /* codec-data contains alac atom size and prefix,
8412 * ffmpeg likes it that way, not quite gst-ish though ...*/
8413 buf = gst_buffer_new_and_alloc (len);
8414 gst_buffer_fill (buf, 0, alac->data, len);
8415 gst_caps_set_simple (stream->caps,
8416 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8417 gst_buffer_unref (buf);
8419 stream->bytes_per_frame = QT_UINT32 (alac_data + 12);
8420 stream->n_channels = QT_UINT8 (alac_data + 21);
8421 stream->rate = QT_UINT32 (alac_data + 32);
8424 gst_caps_set_simple (stream->caps,
8425 "samplesize", G_TYPE_INT, samplesize, NULL);
8433 gint len = QT_UINT32 (stsd_data);
8436 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
8439 gst_buffer_fill (buf, 0, stsd_data + 0x34, len - 0x34);
8441 /* If we have enough data, let's try to get the 'damr' atom. See
8442 * the 3GPP container spec (26.244) for more details. */
8443 if ((len - 0x34) > 8 &&
8444 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
8446 list = gst_tag_list_new_empty ();
8447 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
8448 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
8451 gst_caps_set_simple (stream->caps,
8452 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8453 gst_buffer_unref (buf);
8458 GST_INFO_OBJECT (qtdemux,
8459 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
8463 GST_INFO_OBJECT (qtdemux,
8464 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
8465 GST_FOURCC_ARGS (fourcc), stream->caps);
8467 } else if (stream->subtype == FOURCC_strm) {
8468 if (fourcc == FOURCC_rtsp) {
8469 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
8471 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
8472 GST_FOURCC_ARGS (fourcc));
8473 goto unknown_stream;
8475 stream->sampled = TRUE;
8476 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
8477 || stream->subtype == FOURCC_sbtl) {
8479 stream->sampled = TRUE;
8480 stream->sparse = TRUE;
8485 qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
8487 list = gst_tag_list_new_empty ();
8488 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
8489 GST_TAG_SUBTITLE_CODEC, codec, NULL);
8494 /* hunt for sort-of codec data */
8501 /* look for palette in a stsd->mp4s->esds sub-atom */
8502 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
8504 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
8507 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
8511 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
8515 GST_INFO_OBJECT (qtdemux,
8516 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
8519 GST_INFO_OBJECT (qtdemux,
8520 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
8521 GST_FOURCC_ARGS (fourcc), stream->caps);
8523 /* everything in 1 sample */
8524 stream->sampled = TRUE;
8527 qtdemux_generic_caps (qtdemux, stream, fourcc, stsd_data, &codec);
8529 if (stream->caps == NULL)
8530 goto unknown_stream;
8533 list = gst_tag_list_new_empty ();
8534 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
8535 GST_TAG_SUBTITLE_CODEC, codec, NULL);
8541 /* promote to sampled format */
8542 if (stream->fourcc == FOURCC_samr) {
8543 /* force mono 8000 Hz for AMR */
8544 stream->sampled = TRUE;
8545 stream->n_channels = 1;
8546 stream->rate = 8000;
8547 } else if (stream->fourcc == FOURCC_sawb) {
8548 /* force mono 16000 Hz for AMR-WB */
8549 stream->sampled = TRUE;
8550 stream->n_channels = 1;
8551 stream->rate = 16000;
8552 } else if (stream->fourcc == FOURCC_mp4a) {
8553 stream->sampled = TRUE;
8556 /* collect sample information */
8557 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
8558 goto samples_failed;
8560 if (qtdemux->fragmented) {
8564 /* need all moov samples as basis; probably not many if any at all */
8565 /* prevent moof parsing taking of at this time */
8566 offset = qtdemux->moof_offset;
8567 qtdemux->moof_offset = 0;
8568 if (stream->n_samples &&
8569 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
8570 qtdemux->moof_offset = offset;
8571 goto samples_failed;
8573 qtdemux->moof_offset = 0;
8574 /* movie duration more reliable in this case (e.g. mehd) */
8575 if (qtdemux->segment.duration &&
8576 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
8577 stream->duration = gst_util_uint64_scale (qtdemux->segment.duration,
8578 stream->timescale, GST_SECOND);
8579 /* need defaults for fragments */
8580 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
8583 /* configure segments */
8584 if (!qtdemux_parse_segments (qtdemux, stream, trak))
8585 goto segments_failed;
8587 /* add some language tag, if useful */
8588 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
8589 strcmp (stream->lang_id, "und")) {
8590 const gchar *lang_code;
8593 list = gst_tag_list_new_empty ();
8595 /* convert ISO 639-2 code to ISO 639-1 */
8596 lang_code = gst_tag_get_language_code (stream->lang_id);
8597 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
8598 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
8601 /* now we are ready to add the stream */
8602 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
8603 goto too_many_streams;
8605 if (!qtdemux->got_moov) {
8606 stream->pending_tags = list;
8607 qtdemux->streams[qtdemux->n_streams] = stream;
8608 qtdemux->n_streams++;
8609 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
8617 GST_INFO_OBJECT (qtdemux, "skip disabled track");
8624 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8625 (_("This file is corrupt and cannot be played.")), (NULL));
8632 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
8640 /* we posted an error already */
8641 /* free stbl sub-atoms */
8642 gst_qtdemux_stbl_free (stream);
8649 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
8657 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
8658 GST_FOURCC_ARGS (stream->subtype));
8665 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
8666 (_("This file contains too many streams. Only playing first %d"),
8667 GST_QTDEMUX_MAX_STREAMS), (NULL));
8672 /* If we can estimate the overall bitrate, and don't have information about the
8673 * stream bitrate for exactly one stream, this guesses the stream bitrate as
8674 * the overall bitrate minus the sum of the bitrates of all other streams. This
8675 * should be useful for the common case where we have one audio and one video
8676 * stream and can estimate the bitrate of one, but not the other. */
8678 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
8680 QtDemuxStream *stream = NULL;
8681 gint64 size, duration, sys_bitrate, sum_bitrate = 0;
8685 if (qtdemux->fragmented)
8688 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
8690 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
8692 GST_DEBUG_OBJECT (qtdemux,
8693 "Size in bytes of the stream not known - bailing");
8697 /* Subtract the header size */
8698 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
8699 size, qtdemux->header_size);
8701 if (size < qtdemux->header_size)
8704 size = size - qtdemux->header_size;
8706 if (!gst_qtdemux_get_duration (qtdemux, &duration) ||
8707 duration == GST_CLOCK_TIME_NONE) {
8708 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
8712 for (i = 0; i < qtdemux->n_streams; i++) {
8713 switch (qtdemux->streams[i]->subtype) {
8716 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
8717 qtdemux->streams[i]->caps);
8718 /* retrieve bitrate, prefer avg then max */
8720 if (qtdemux->streams[i]->pending_tags) {
8721 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
8722 GST_TAG_MAXIMUM_BITRATE, &bitrate);
8723 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
8724 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
8725 GST_TAG_NOMINAL_BITRATE, &bitrate);
8726 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
8727 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
8728 GST_TAG_BITRATE, &bitrate);
8729 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
8732 sum_bitrate += bitrate;
8735 GST_DEBUG_OBJECT (qtdemux,
8736 ">1 stream with unknown bitrate - bailing");
8739 stream = qtdemux->streams[i];
8743 /* For other subtypes, we assume no significant impact on bitrate */
8749 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
8753 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
8755 if (sys_bitrate < sum_bitrate) {
8756 /* This can happen, since sum_bitrate might be derived from maximum
8757 * bitrates and not average bitrates */
8758 GST_DEBUG_OBJECT (qtdemux,
8759 "System bitrate less than sum bitrate - bailing");
8763 bitrate = sys_bitrate - sum_bitrate;
8764 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
8765 ", Stream bitrate = %u", sys_bitrate, bitrate);
8767 if (!stream->pending_tags)
8768 stream->pending_tags = gst_tag_list_new_empty ();
8770 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
8771 GST_TAG_BITRATE, bitrate, NULL);
8774 static GstFlowReturn
8775 qtdemux_prepare_streams (GstQTDemux * qtdemux)
8778 GstFlowReturn ret = GST_FLOW_OK;
8780 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
8782 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
8783 QtDemuxStream *stream = qtdemux->streams[i];
8784 guint32 sample_num = 0;
8788 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
8789 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
8791 if (qtdemux->fragmented) {
8792 /* need all moov samples first */
8793 GST_OBJECT_LOCK (qtdemux);
8794 while (stream->n_samples == 0)
8795 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
8797 GST_OBJECT_UNLOCK (qtdemux);
8799 /* discard any stray moof */
8800 qtdemux->moof_offset = 0;
8803 /* prepare braking */
8804 if (ret != GST_FLOW_ERROR)
8807 /* in pull mode, we should have parsed some sample info by now;
8808 * and quite some code will not handle no samples.
8809 * in push mode, we'll just have to deal with it */
8810 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
8811 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
8812 gst_qtdemux_remove_stream (qtdemux, i);
8817 /* parse number of initial sample to set frame rate cap */
8818 while (sample_num < stream->n_samples && sample_num < samples) {
8819 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
8823 /* collect and sort durations */
8824 samples = MIN (stream->stbl_index + 1, samples);
8825 GST_DEBUG_OBJECT (qtdemux, "%d samples for framerate", samples);
8827 durations = g_array_sized_new (FALSE, FALSE, sizeof (guint32), samples);
8829 while (sample_num < samples) {
8830 g_array_append_val (durations, stream->samples[sample_num].duration);
8833 g_array_sort (durations, less_than);
8834 stream->min_duration = g_array_index (durations, guint32, samples / 2);
8835 g_array_free (durations, TRUE);
8842 static GstFlowReturn
8843 qtdemux_expose_streams (GstQTDemux * qtdemux)
8846 GstFlowReturn ret = GST_FLOW_OK;
8847 GSList *oldpads = NULL;
8850 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
8852 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
8853 QtDemuxStream *stream = qtdemux->streams[i];
8854 GstPad *oldpad = stream->pad;
8857 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
8858 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
8860 if ((stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl) &&
8861 stream->track_id == qtdemux->chapters_track_id) {
8862 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
8863 so that it doesn't look like a subtitle track */
8864 gst_qtdemux_remove_stream (qtdemux, i);
8869 /* now we have all info and can expose */
8870 list = stream->pending_tags;
8871 stream->pending_tags = NULL;
8873 oldpads = g_slist_prepend (oldpads, oldpad);
8874 gst_qtdemux_add_stream (qtdemux, stream, list);
8877 gst_qtdemux_guess_bitrate (qtdemux);
8879 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
8881 for (iter = oldpads; iter; iter = g_slist_next (iter)) {
8882 GstPad *oldpad = iter->data;
8884 gst_pad_push_event (oldpad, gst_event_new_eos ());
8885 gst_pad_set_active (oldpad, FALSE);
8886 gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
8887 gst_object_unref (oldpad);
8890 /* check if we should post a redirect in case there is a single trak
8891 * and it is a redirecting trak */
8892 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
8895 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
8896 "an external content");
8897 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
8898 gst_structure_new ("redirect",
8899 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
8901 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
8902 qtdemux->posted_redirect = TRUE;
8905 for (i = 0; i < qtdemux->n_streams; i++) {
8906 QtDemuxStream *stream = qtdemux->streams[i];
8908 qtdemux_do_allocation (qtdemux, stream);
8911 qtdemux->exposed = TRUE;
8915 /* check if major or compatible brand is 3GP */
8916 static inline gboolean
8917 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
8920 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
8921 GST_MAKE_FOURCC ('3', 'g', 0, 0));
8922 } else if (qtdemux->comp_brands != NULL) {
8926 gboolean res = FALSE;
8928 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
8932 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
8933 GST_MAKE_FOURCC ('3', 'g', 0, 0));
8937 gst_buffer_unmap (qtdemux->comp_brands, &map);
8944 /* check if tag is a spec'ed 3GP tag keyword storing a string */
8945 static inline gboolean
8946 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
8948 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
8949 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
8950 || fourcc == FOURCC_albm;
8954 qtdemux_tag_add_location (GstQTDemux * qtdemux, const char *tag,
8955 const char *dummy, GNode * node)
8957 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
8961 gdouble longitude, latitude, altitude;
8964 len = QT_UINT32 (node->data);
8971 /* TODO: language code skipped */
8973 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
8976 /* do not alarm in trivial case, but bail out otherwise */
8977 if (*(data + offset) != 0) {
8978 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
8982 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
8983 GST_TAG_GEO_LOCATION_NAME, name, NULL);
8984 offset += strlen (name);
8988 if (len < offset + 2 + 4 + 4 + 4)
8991 /* +1 +1 = skip null-terminator and location role byte */
8993 /* table in spec says unsigned, semantics say negative has meaning ... */
8994 longitude = QT_SFP32 (data + offset);
8997 latitude = QT_SFP32 (data + offset);
9000 altitude = QT_SFP32 (data + offset);
9002 /* one invalid means all are invalid */
9003 if (longitude >= -180.0 && longitude <= 180.0 &&
9004 latitude >= -90.0 && latitude <= 90.0) {
9005 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9006 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
9007 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
9008 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
9011 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
9018 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
9025 qtdemux_tag_add_year (GstQTDemux * qtdemux, const char *tag, const char *dummy,
9032 len = QT_UINT32 (node->data);
9036 y = QT_UINT16 ((guint8 *) node->data + 12);
9038 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
9041 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
9043 date = g_date_new_dmy (1, 1, y);
9044 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, date, NULL);
9049 qtdemux_tag_add_classification (GstQTDemux * qtdemux, const char *tag,
9050 const char *dummy, GNode * node)
9053 char *tag_str = NULL;
9058 len = QT_UINT32 (node->data);
9063 entity = (guint8 *) node->data + offset;
9064 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
9065 GST_DEBUG_OBJECT (qtdemux,
9066 "classification info: %c%c%c%c invalid classification entity",
9067 entity[0], entity[1], entity[2], entity[3]);
9072 table = QT_UINT16 ((guint8 *) node->data + offset);
9074 /* Language code skipped */
9078 /* Tag format: "XXXX://Y[YYYY]/classification info string"
9079 * XXXX: classification entity, fixed length 4 chars.
9080 * Y[YYYY]: classification table, max 5 chars.
9082 tag_str = g_strdup_printf ("----://%u/%s",
9083 table, (char *) node->data + offset);
9085 /* memcpy To be sure we're preserving byte order */
9086 memcpy (tag_str, entity, 4);
9087 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
9089 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_APPEND, tag,
9099 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
9105 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, const char *tag,
9106 const char *dummy, GNode * node)
9108 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
9114 gboolean ret = TRUE;
9115 const gchar *charset = NULL;
9117 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9119 len = QT_UINT32 (data->data);
9120 type = QT_UINT32 ((guint8 *) data->data + 8);
9121 if (type == 0x00000001 && len > 16) {
9122 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
9125 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
9126 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s,
9130 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
9134 len = QT_UINT32 (node->data);
9135 type = QT_UINT32 ((guint8 *) node->data + 4);
9136 if ((type >> 24) == 0xa9) {
9140 /* Type starts with the (C) symbol, so the next data is a list
9141 * of (string size(16), language code(16), string) */
9143 str_len = QT_UINT16 ((guint8 *) node->data + 8);
9144 lang_code = QT_UINT16 ((guint8 *) node->data + 10);
9146 /* the string + fourcc + size + 2 16bit fields,
9147 * means that there are more tags in this atom */
9148 if (len > str_len + 8 + 4) {
9149 /* TODO how to represent the same tag in different languages? */
9150 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
9151 "text alternatives, reading only first one");
9155 len = str_len + 8 + 4; /* remove trailing strings that we don't use */
9156 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
9158 if (lang_code < 0x800) { /* MAC encoded string */
9161 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
9162 QT_FOURCC ((guint8 *) node->data + 4))) {
9163 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
9165 /* we go for 3GP style encoding if major brands claims so,
9166 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
9167 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
9168 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
9169 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
9171 /* 16-bit Language code is ignored here as well */
9172 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
9179 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
9180 ret = FALSE; /* may have to fallback */
9185 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
9186 charset, NULL, NULL, &err);
9188 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
9189 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
9194 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
9195 len - offset, env_vars);
9198 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
9199 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s, NULL);
9203 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
9210 qtdemux_tag_add_str (GstQTDemux * qtdemux, const char *tag,
9211 const char *dummy, GNode * node)
9213 qtdemux_tag_add_str_full (qtdemux, tag, dummy, node);
9217 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, const char *tag,
9218 const char *dummy, GNode * node)
9220 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
9222 char *s, *t, *k = NULL;
9227 /* first try normal string tag if major brand not 3GP */
9228 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
9229 if (!qtdemux_tag_add_str_full (qtdemux, tag, dummy, node)) {
9230 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
9231 * let's try it 3gpp way after minor safety check */
9233 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
9239 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
9243 len = QT_UINT32 (data);
9247 count = QT_UINT8 (data + 14);
9249 for (; count; count--) {
9252 if (offset + 1 > len)
9254 slen = QT_UINT8 (data + offset);
9256 if (offset + slen > len)
9258 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
9261 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
9263 t = g_strjoin (",", k, s, NULL);
9271 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
9278 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
9279 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, k, NULL);
9288 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
9294 qtdemux_tag_add_num (GstQTDemux * qtdemux, const char *tag1,
9295 const char *tag2, GNode * node)
9302 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9304 len = QT_UINT32 (data->data);
9305 type = QT_UINT32 ((guint8 *) data->data + 8);
9306 if (type == 0x00000000 && len >= 22) {
9307 n1 = QT_UINT16 ((guint8 *) data->data + 18);
9308 n2 = QT_UINT16 ((guint8 *) data->data + 20);
9310 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
9311 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9315 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
9316 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9324 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
9332 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9334 len = QT_UINT32 (data->data);
9335 type = QT_UINT32 ((guint8 *) data->data + 8);
9336 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
9337 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
9338 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
9339 n1 = QT_UINT16 ((guint8 *) data->data + 16);
9341 /* do not add bpm=0 */
9342 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
9343 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9344 tag1, (gdouble) n1, NULL);
9351 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, const char *tag1,
9352 const char *dummy, GNode * node)
9359 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9361 len = QT_UINT32 (data->data);
9362 type = QT_UINT32 ((guint8 *) data->data + 8);
9363 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
9364 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
9365 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
9366 num = QT_UINT32 ((guint8 *) data->data + 16);
9368 /* do not add num=0 */
9369 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
9370 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9378 qtdemux_tag_add_covr (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
9386 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9388 len = QT_UINT32 (data->data);
9389 type = QT_UINT32 ((guint8 *) data->data + 8);
9390 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
9391 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
9393 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
9394 len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
9395 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
9396 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9397 tag1, sample, NULL);
9398 gst_sample_unref (sample);
9405 qtdemux_tag_add_date (GstQTDemux * qtdemux, const char *tag, const char *dummy,
9413 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9415 len = QT_UINT32 (data->data);
9416 type = QT_UINT32 ((guint8 *) data->data + 8);
9417 if (type == 0x00000001 && len > 16) {
9418 guint y, m = 1, d = 1;
9421 s = g_strndup ((char *) data->data + 16, len - 16);
9422 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
9423 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
9424 if (ret >= 1 && y > 1500 && y < 3000) {
9427 date = g_date_new_dmy (d, m, y);
9428 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag,
9432 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
9440 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, const char *tag, const char *dummy,
9445 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9447 /* re-route to normal string tag if major brand says so
9448 * or no data atom and compatible brand suggests so */
9449 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
9450 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
9451 qtdemux_tag_add_str (qtdemux, tag, dummy, node);
9458 len = QT_UINT32 (data->data);
9459 type = QT_UINT32 ((guint8 *) data->data + 8);
9460 if (type == 0x00000000 && len >= 18) {
9461 n = QT_UINT16 ((guint8 *) data->data + 16);
9465 genre = gst_tag_id3_genre_get (n - 1);
9466 if (genre != NULL) {
9467 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
9468 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9477 qtdemux_add_double_tag_from_str (GstQTDemux * demux, const gchar * tag,
9478 guint8 * data, guint32 datasize)
9483 /* make a copy to have \0 at the end */
9484 datacopy = g_strndup ((gchar *) data, datasize);
9486 /* convert the str to double */
9487 if (sscanf (datacopy, "%lf", &value) == 1) {
9488 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
9489 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_REPLACE, tag, value, NULL);
9491 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
9499 qtdemux_tag_add_revdns (GstQTDemux * demux, const char *tag,
9500 const char *tag_bis, GNode * node)
9509 const gchar *meanstr;
9510 const gchar *namestr;
9512 /* checking the whole ---- atom size for consistency */
9513 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
9514 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
9518 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
9520 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
9524 meansize = QT_UINT32 (mean->data);
9525 if (meansize <= 12) {
9526 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
9529 meanstr = ((gchar *) mean->data) + 12;
9532 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
9534 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
9538 namesize = QT_UINT32 (name->data);
9539 if (namesize <= 12) {
9540 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
9543 namestr = ((gchar *) name->data) + 12;
9551 * uint24 - data type
9555 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9557 GST_WARNING_OBJECT (demux, "No data atom in this tag");
9560 datasize = QT_UINT32 (data->data);
9561 if (datasize <= 16) {
9562 GST_WARNING_OBJECT (demux, "Data atom too small");
9565 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
9567 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
9568 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
9571 const gchar name[28];
9572 const gchar tag[28];
9575 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
9576 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
9577 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
9578 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
9579 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
9580 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
9581 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
9582 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
9586 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
9587 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
9588 switch (gst_tag_get_type (tags[i].tag)) {
9590 qtdemux_add_double_tag_from_str (demux, tags[i].tag,
9591 ((guint8 *) data->data) + 16, datasize - 16);
9594 qtdemux_tag_add_str (demux, tags[i].tag, NULL, node);
9603 if (i == G_N_ELEMENTS (tags))
9613 #ifndef GST_DISABLE_GST_DEBUG
9618 meanstr_dbg = g_strndup (meanstr, meansize);
9619 namestr_dbg = g_strndup (namestr, namesize);
9621 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
9622 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
9624 g_free (namestr_dbg);
9625 g_free (meanstr_dbg);
9632 qtdemux_tag_add_id32 (GstQTDemux * demux, const char *tag,
9633 const char *tag_bis, GNode * node)
9638 GstTagList *taglist = NULL;
9640 GST_LOG_OBJECT (demux, "parsing ID32");
9643 len = GST_READ_UINT32_BE (data);
9645 /* need at least full box and language tag */
9649 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
9650 gst_buffer_fill (buf, 0, data + 14, len - 14);
9652 taglist = gst_tag_list_from_id3v2_tag (buf);
9654 GST_LOG_OBJECT (demux, "parsing ok");
9655 gst_tag_list_insert (demux->tag_list, taglist, GST_TAG_MERGE_KEEP);
9657 GST_LOG_OBJECT (demux, "parsing failed");
9661 gst_tag_list_unref (taglist);
9663 gst_buffer_unref (buf);
9666 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux,
9667 const char *tag, const char *tag_bis, GNode * node);
9670 FOURCC_pcst -> if media is a podcast -> bool
9671 FOURCC_cpil -> if media is part of a compilation -> bool
9672 FOURCC_pgap -> if media is part of a gapless context -> bool
9673 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
9679 const gchar *gst_tag;
9680 const gchar *gst_tag_bis;
9681 const GstQTDemuxAddTagFunc func;
9684 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
9685 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
9686 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
9687 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
9688 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
9689 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
9690 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
9691 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
9692 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
9693 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
9694 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
9695 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
9696 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
9697 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
9698 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
9699 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
9700 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
9701 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
9702 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
9703 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
9704 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
9705 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
9706 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
9707 qtdemux_tag_add_num}, {
9708 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
9709 qtdemux_tag_add_num}, {
9710 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
9711 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
9712 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
9713 FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
9714 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
9715 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
9716 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
9717 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
9718 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
9719 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
9720 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
9721 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
9722 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
9723 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
9724 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
9725 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
9726 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
9727 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
9728 qtdemux_tag_add_classification}, {
9730 /* This is a special case, some tags are stored in this
9731 * 'reverse dns naming', according to:
9732 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
9735 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
9736 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
9737 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
9741 qtdemux_tag_add_blob (GNode * node, GstQTDemux * demux)
9754 len = QT_UINT32 (data);
9755 buf = gst_buffer_new_and_alloc (len);
9756 gst_buffer_fill (buf, 0, data, len);
9758 /* heuristic to determine style of tag */
9759 if (QT_FOURCC (data + 4) == FOURCC_____ ||
9760 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
9762 else if (demux->major_brand == FOURCC_qt__)
9763 style = "quicktime";
9764 /* fall back to assuming iso/3gp tag style */
9768 /* santize the name for the caps. */
9769 for (i = 0; i < 4; i++) {
9770 guint8 d = data[4 + i];
9771 if (g_ascii_isalnum (d))
9772 ndata[i] = g_ascii_tolower (d);
9777 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
9778 ndata[0], ndata[1], ndata[2], ndata[3]);
9779 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
9781 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
9782 sample = gst_sample_new (buf, NULL, NULL, s);
9783 gst_buffer_unref (buf);
9784 g_free (media_type);
9786 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
9789 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_APPEND,
9790 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
9792 gst_sample_unref (sample);
9796 qtdemux_parse_udta (GstQTDemux * qtdemux, GNode * udta)
9804 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
9806 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
9808 GST_LOG_OBJECT (qtdemux, "no ilst");
9813 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
9816 GST_DEBUG_OBJECT (qtdemux, "new tag list");
9817 if (!qtdemux->tag_list) {
9818 qtdemux->tag_list = gst_tag_list_new_empty ();
9819 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
9821 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
9825 while (i < G_N_ELEMENTS (add_funcs)) {
9826 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
9830 len = QT_UINT32 (node->data);
9832 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
9833 GST_FOURCC_ARGS (add_funcs[i].fourcc));
9835 add_funcs[i].func (qtdemux, add_funcs[i].gst_tag,
9836 add_funcs[i].gst_tag_bis, node);
9838 g_node_destroy (node);
9844 /* parsed nodes have been removed, pass along remainder as blob */
9845 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
9846 (GNodeForeachFunc) qtdemux_tag_add_blob, qtdemux);
9848 /* parse up XMP_ node if existing */
9849 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
9852 GstTagList *taglist;
9854 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
9855 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
9856 taglist = gst_tag_list_from_xmp_buffer (buf);
9857 gst_buffer_unref (buf);
9859 qtdemux_handle_xmp_taglist (qtdemux, taglist);
9861 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
9868 GstStructure *structure; /* helper for sort function */
9870 guint min_req_bitrate;
9871 guint min_req_qt_version;
9875 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
9877 GstQtReference *ref_a = (GstQtReference *) a;
9878 GstQtReference *ref_b = (GstQtReference *) b;
9880 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
9881 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
9883 /* known bitrates go before unknown; higher bitrates go first */
9884 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
9887 /* sort the redirects and post a message for the application.
9890 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
9892 GstQtReference *best;
9895 GValue list_val = { 0, };
9898 g_assert (references != NULL);
9900 references = g_list_sort (references, qtdemux_redirects_sort_func);
9902 best = (GstQtReference *) references->data;
9904 g_value_init (&list_val, GST_TYPE_LIST);
9906 for (l = references; l != NULL; l = l->next) {
9907 GstQtReference *ref = (GstQtReference *) l->data;
9908 GValue struct_val = { 0, };
9910 ref->structure = gst_structure_new ("redirect",
9911 "new-location", G_TYPE_STRING, ref->location, NULL);
9913 if (ref->min_req_bitrate > 0) {
9914 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
9915 ref->min_req_bitrate, NULL);
9918 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
9919 g_value_set_boxed (&struct_val, ref->structure);
9920 gst_value_list_append_value (&list_val, &struct_val);
9921 g_value_unset (&struct_val);
9922 /* don't free anything here yet, since we need best->structure below */
9925 g_assert (best != NULL);
9926 s = gst_structure_copy (best->structure);
9928 if (g_list_length (references) > 1) {
9929 gst_structure_set_value (s, "locations", &list_val);
9932 g_value_unset (&list_val);
9934 for (l = references; l != NULL; l = l->next) {
9935 GstQtReference *ref = (GstQtReference *) l->data;
9937 gst_structure_free (ref->structure);
9938 g_free (ref->location);
9941 g_list_free (references);
9943 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
9944 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
9945 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
9946 qtdemux->posted_redirect = TRUE;
9949 /* look for redirect nodes, collect all redirect information and
9953 qtdemux_parse_redirects (GstQTDemux * qtdemux)
9955 GNode *rmra, *rmda, *rdrf;
9957 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
9959 GList *redirects = NULL;
9961 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
9963 GstQtReference ref = { NULL, NULL, 0, 0 };
9966 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
9967 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
9968 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
9969 ref.min_req_bitrate);
9972 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
9973 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
9974 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
9976 #ifndef GST_DISABLE_GST_DEBUG
9977 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
9979 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
9981 GST_LOG_OBJECT (qtdemux,
9982 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
9983 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
9984 bitmask, check_type);
9985 if (package == FOURCC_qtim && check_type == 0) {
9986 ref.min_req_qt_version = version;
9990 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
9995 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
9996 ref_data = (guint8 *) rdrf->data + 20;
9997 if (ref_type == FOURCC_alis) {
9998 guint record_len, record_version, fn_len;
10000 /* MacOSX alias record, google for alias-layout.txt */
10001 record_len = QT_UINT16 (ref_data + 4);
10002 record_version = QT_UINT16 (ref_data + 4 + 2);
10003 fn_len = QT_UINT8 (ref_data + 50);
10004 if (record_len > 50 && record_version == 2 && fn_len > 0) {
10005 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
10007 } else if (ref_type == FOURCC_url_) {
10008 ref.location = g_strdup ((gchar *) ref_data);
10010 GST_DEBUG_OBJECT (qtdemux,
10011 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
10012 GST_FOURCC_ARGS (ref_type));
10014 if (ref.location != NULL) {
10015 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
10016 redirects = g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
10018 GST_WARNING_OBJECT (qtdemux,
10019 "Failed to extract redirect location from rdrf atom");
10023 /* look for others */
10024 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
10027 if (redirects != NULL) {
10028 qtdemux_process_redirects (qtdemux, redirects);
10034 static GstTagList *
10035 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
10039 if (tags == NULL) {
10040 tags = gst_tag_list_new_empty ();
10041 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
10044 if (qtdemux->major_brand == FOURCC_mjp2)
10045 fmt = "Motion JPEG 2000";
10046 else if ((qtdemux->major_brand & 0xffff) == GST_MAKE_FOURCC ('3', 'g', 0, 0))
10048 else if (qtdemux->major_brand == FOURCC_qt__)
10050 else if (qtdemux->fragmented)
10053 fmt = "ISO MP4/M4A";
10055 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
10056 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
10058 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
10064 /* we have read th complete moov node now.
10065 * This function parses all of the relevant info, creates the traks and
10066 * prepares all data structures for playback
10069 qtdemux_parse_tree (GstQTDemux * qtdemux)
10076 guint64 creation_time;
10077 GstDateTime *datetime = NULL;
10080 /* make sure we have a usable taglist */
10081 if (!qtdemux->tag_list) {
10082 qtdemux->tag_list = gst_tag_list_new_empty ();
10083 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
10085 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
10088 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
10089 if (mvhd == NULL) {
10090 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
10091 return qtdemux_parse_redirects (qtdemux);
10094 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
10095 if (version == 1) {
10096 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
10097 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
10098 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
10099 } else if (version == 0) {
10100 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
10101 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
10102 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
10104 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
10108 /* Moving qt creation time (secs since 1904) to unix time */
10109 if (creation_time != 0) {
10110 /* Try to use epoch first as it should be faster and more commonly found */
10111 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
10114 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
10115 /* some data cleansing sanity */
10116 g_get_current_time (&now);
10117 if (now.tv_sec + 24 * 3600 < creation_time) {
10118 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
10120 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
10123 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
10124 GDateTime *dt, *dt_local;
10126 dt = g_date_time_add_seconds (base_dt, creation_time);
10127 dt_local = g_date_time_to_local (dt);
10128 datetime = gst_date_time_new_from_g_date_time (dt_local);
10130 g_date_time_unref (base_dt);
10131 g_date_time_unref (dt);
10135 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
10136 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
10138 gst_date_time_unref (datetime);
10141 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
10142 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
10144 /* check for fragmented file and get some (default) data */
10145 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
10148 GstByteReader mehd_data;
10150 /* let track parsing or anyone know weird stuff might happen ... */
10151 qtdemux->fragmented = TRUE;
10153 /* compensate for total duration */
10154 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
10156 qtdemux_parse_mehd (qtdemux, &mehd_data);
10159 /* parse all traks */
10160 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
10162 qtdemux_parse_trak (qtdemux, trak);
10163 /* iterate all siblings */
10164 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
10167 /* set duration in the segment info */
10168 gst_qtdemux_get_duration (qtdemux, &duration);
10170 qtdemux->segment.duration = duration;
10171 /* also do not exceed duration; stop is set that way post seek anyway,
10172 * and segment activation falls back to duration,
10173 * whereas loop only checks stop, so let's align this here as well */
10174 qtdemux->segment.stop = duration;
10178 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
10180 qtdemux_parse_udta (qtdemux, udta);
10182 GST_LOG_OBJECT (qtdemux, "No udta node found.");
10185 /* maybe also some tags in meta box */
10186 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
10188 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
10189 qtdemux_parse_udta (qtdemux, udta);
10191 GST_LOG_OBJECT (qtdemux, "No meta node found.");
10194 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
10199 /* taken from ffmpeg */
10201 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
10213 len = (len << 7) | (c & 0x7f);
10221 /* this can change the codec originally present in @list */
10223 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
10224 GNode * esds, GstTagList * list)
10226 int len = QT_UINT32 (esds->data);
10227 guint8 *ptr = esds->data;
10228 guint8 *end = ptr + len;
10230 guint8 *data_ptr = NULL;
10232 guint8 object_type_id = 0;
10233 const char *codec_name = NULL;
10234 GstCaps *caps = NULL;
10236 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
10238 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
10240 while (ptr + 1 < end) {
10241 tag = QT_UINT8 (ptr);
10242 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
10244 len = read_descr_size (ptr, end, &ptr);
10245 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
10247 /* Check the stated amount of data is available for reading */
10248 if (len < 0 || ptr + len > end)
10252 case ES_DESCRIPTOR_TAG:
10253 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
10254 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
10257 case DECODER_CONFIG_DESC_TAG:{
10258 guint max_bitrate, avg_bitrate;
10260 object_type_id = QT_UINT8 (ptr);
10261 max_bitrate = QT_UINT32 (ptr + 5);
10262 avg_bitrate = QT_UINT32 (ptr + 9);
10263 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
10264 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
10265 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
10266 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
10267 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
10268 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
10269 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
10270 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
10272 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
10273 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
10274 avg_bitrate, NULL);
10279 case DECODER_SPECIFIC_INFO_TAG:
10280 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
10281 if (object_type_id == 0xe0 && len == 0x40) {
10287 GST_DEBUG_OBJECT (qtdemux,
10288 "Have VOBSUB palette. Creating palette event");
10289 /* move to decConfigDescr data and read palette */
10291 for (i = 0; i < 16; i++) {
10292 clut[i] = QT_UINT32 (data);
10296 s = gst_structure_new ("application/x-gst-dvd", "event",
10297 G_TYPE_STRING, "dvd-spu-clut-change",
10298 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
10299 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
10300 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
10301 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
10302 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
10303 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
10304 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
10305 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
10308 /* store event and trigger custom processing */
10309 stream->pending_event =
10310 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
10312 /* Generic codec_data handler puts it on the caps */
10319 case SL_CONFIG_DESC_TAG:
10320 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
10324 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
10326 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
10332 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
10333 * in use, and should also be used to override some other parameters for some
10335 switch (object_type_id) {
10336 case 0x20: /* MPEG-4 */
10337 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
10338 * profile_and_level_indication */
10339 if (data_ptr != NULL && data_len >= 5 &&
10340 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
10341 gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
10342 data_ptr + 4, data_len - 4);
10344 break; /* Nothing special needed here */
10345 case 0x21: /* H.264 */
10346 codec_name = "H.264 / AVC";
10347 caps = gst_caps_new_simple ("video/x-h264",
10348 "stream-format", G_TYPE_STRING, "avc",
10349 "alignment", G_TYPE_STRING, "au", NULL);
10351 case 0x40: /* AAC (any) */
10352 case 0x66: /* AAC Main */
10353 case 0x67: /* AAC LC */
10354 case 0x68: /* AAC SSR */
10355 /* Override channels and rate based on the codec_data, as it's often
10357 /* Only do so for basic setup without HE-AAC extension */
10358 if (data_ptr && data_len == 2) {
10359 guint channels, rateindex, rate;
10361 /* FIXME: add gst_codec_utils_aac_get_{channels|sample_rate}()? */
10362 channels = (data_ptr[1] & 0x7f) >> 3;
10363 if (channels > 0 && channels < 7) {
10364 stream->n_channels = channels;
10365 } else if (channels == 7) {
10366 stream->n_channels = 8;
10369 rateindex = ((data_ptr[0] & 0x7) << 1) | ((data_ptr[1] & 0x80) >> 7);
10370 rate = gst_codec_utils_aac_get_sample_rate_from_index (rateindex);
10372 stream->rate = rate;
10375 /* Set level and profile if possible */
10376 if (data_ptr != NULL && data_len >= 2) {
10377 gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
10378 data_ptr, data_len);
10381 case 0x60: /* MPEG-2, various profiles */
10387 codec_name = "MPEG-2 video";
10388 caps = gst_caps_new_simple ("video/mpeg",
10389 "mpegversion", G_TYPE_INT, 2,
10390 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
10392 case 0x69: /* MPEG-2 BC audio */
10393 case 0x6B: /* MPEG-1 audio */
10394 caps = gst_caps_new_simple ("audio/mpeg",
10395 "mpegversion", G_TYPE_INT, 1, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
10396 codec_name = "MPEG-1 audio";
10398 case 0x6A: /* MPEG-1 */
10399 codec_name = "MPEG-1 video";
10400 caps = gst_caps_new_simple ("video/mpeg",
10401 "mpegversion", G_TYPE_INT, 1,
10402 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
10404 case 0x6C: /* MJPEG */
10405 caps = gst_caps_new_empty_simple ("image/jpeg");
10406 codec_name = "Motion-JPEG";
10408 case 0x6D: /* PNG */
10409 caps = gst_caps_new_empty_simple ("image/png");
10410 codec_name = "PNG still images";
10412 case 0x6E: /* JPEG2000 */
10413 codec_name = "JPEG-2000";
10414 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
10416 case 0xA4: /* Dirac */
10417 codec_name = "Dirac";
10418 caps = gst_caps_new_empty_simple ("video/x-dirac");
10420 case 0xA5: /* AC3 */
10421 codec_name = "AC-3 audio";
10422 caps = gst_caps_new_simple ("audio/x-ac3",
10423 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
10425 case 0xE1: /* QCELP */
10426 /* QCELP, the codec_data is a riff tag (little endian) with
10427 * 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). */
10428 caps = gst_caps_new_empty_simple ("audio/qcelp");
10429 codec_name = "QCELP";
10435 /* If we have a replacement caps, then change our caps for this stream */
10437 gst_caps_unref (stream->caps);
10438 stream->caps = caps;
10441 if (codec_name && list)
10442 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
10443 GST_TAG_AUDIO_CODEC, codec_name, NULL);
10445 /* Add the codec_data attribute to caps, if we have it */
10449 buffer = gst_buffer_new_and_alloc (data_len);
10450 gst_buffer_fill (buffer, 0, data_ptr, data_len);
10452 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
10453 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
10455 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
10457 gst_buffer_unref (buffer);
10462 #define _codec(name) \
10464 if (codec_name) { \
10465 *codec_name = g_strdup (name); \
10470 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
10471 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
10473 GstCaps *caps = NULL;
10474 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
10477 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
10478 _codec ("PNG still images");
10479 caps = gst_caps_new_empty_simple ("image/png");
10481 case GST_MAKE_FOURCC ('j', 'p', 'e', 'g'):
10482 _codec ("JPEG still images");
10483 caps = gst_caps_new_empty_simple ("image/jpeg");
10485 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
10486 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
10487 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
10488 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
10489 _codec ("Motion-JPEG");
10490 caps = gst_caps_new_empty_simple ("image/jpeg");
10492 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
10493 _codec ("Motion-JPEG format B");
10494 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
10496 case GST_MAKE_FOURCC ('m', 'j', 'p', '2'):
10497 _codec ("JPEG-2000");
10498 /* override to what it should be according to spec, avoid palette_data */
10499 stream->bits_per_sample = 24;
10500 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
10502 case GST_MAKE_FOURCC ('S', 'V', 'Q', '3'):
10503 _codec ("Sorensen video v.3");
10504 caps = gst_caps_new_simple ("video/x-svq",
10505 "svqversion", G_TYPE_INT, 3, NULL);
10507 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
10508 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
10509 _codec ("Sorensen video v.1");
10510 caps = gst_caps_new_simple ("video/x-svq",
10511 "svqversion", G_TYPE_INT, 1, NULL);
10513 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
10514 caps = gst_caps_new_empty_simple ("video/x-raw");
10515 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
10516 _codec ("Windows Raw RGB");
10518 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
10522 bps = QT_UINT16 (stsd_data + 98);
10525 format = GST_VIDEO_FORMAT_RGB15;
10528 format = GST_VIDEO_FORMAT_RGB16;
10531 format = GST_VIDEO_FORMAT_RGB;
10534 format = GST_VIDEO_FORMAT_ARGB;
10542 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
10543 format = GST_VIDEO_FORMAT_I420;
10545 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
10546 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
10547 format = GST_VIDEO_FORMAT_I420;
10549 case GST_MAKE_FOURCC ('2', 'v', 'u', 'y'):
10550 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
10551 case GST_MAKE_FOURCC ('v', '2', '1', '0'):
10552 format = GST_VIDEO_FORMAT_UYVY;
10554 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
10555 format = GST_VIDEO_FORMAT_r210;
10557 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
10558 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
10559 _codec ("MPEG-1 video");
10560 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
10561 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
10563 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
10564 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
10565 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
10566 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
10567 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
10568 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
10569 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
10570 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
10571 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
10572 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
10573 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
10574 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
10575 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
10576 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
10577 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
10578 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
10579 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
10580 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
10581 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
10582 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
10583 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
10584 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
10585 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
10586 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
10587 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
10588 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
10589 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
10590 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
10591 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
10592 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
10593 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
10594 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
10595 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
10596 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
10597 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
10598 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
10599 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
10600 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
10601 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
10602 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
10603 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
10604 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
10605 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
10606 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
10607 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
10608 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
10609 _codec ("MPEG-2 video");
10610 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
10611 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
10613 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
10614 _codec ("GIF still images");
10615 caps = gst_caps_new_empty_simple ("image/gif");
10617 case GST_MAKE_FOURCC ('h', '2', '6', '3'):
10618 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
10619 case GST_MAKE_FOURCC ('s', '2', '6', '3'):
10620 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
10622 /* ffmpeg uses the height/width props, don't know why */
10623 caps = gst_caps_new_simple ("video/x-h263",
10624 "variant", G_TYPE_STRING, "itu", NULL);
10626 case GST_MAKE_FOURCC ('m', 'p', '4', 'v'):
10627 case GST_MAKE_FOURCC ('M', 'P', '4', 'V'):
10628 _codec ("MPEG-4 video");
10629 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
10630 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
10632 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
10633 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
10634 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
10635 caps = gst_caps_new_simple ("video/x-msmpeg",
10636 "msmpegversion", G_TYPE_INT, 43, NULL);
10638 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
10640 caps = gst_caps_new_simple ("video/x-divx",
10641 "divxversion", G_TYPE_INT, 3, NULL);
10643 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
10644 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
10646 caps = gst_caps_new_simple ("video/x-divx",
10647 "divxversion", G_TYPE_INT, 4, NULL);
10649 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
10651 caps = gst_caps_new_simple ("video/x-divx",
10652 "divxversion", G_TYPE_INT, 5, NULL);
10655 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
10656 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
10657 case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
10658 case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
10659 case GST_MAKE_FOURCC ('F', 'M', 'P', '4'):
10660 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
10661 caps = gst_caps_new_simple ("video/mpeg",
10662 "mpegversion", G_TYPE_INT, 4, NULL);
10664 *codec_name = g_strdup ("MPEG-4");
10667 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
10668 _codec ("Cinepak");
10669 caps = gst_caps_new_empty_simple ("video/x-cinepak");
10671 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
10672 _codec ("Apple QuickDraw");
10673 caps = gst_caps_new_empty_simple ("video/x-qdrw");
10675 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
10676 _codec ("Apple video");
10677 caps = gst_caps_new_empty_simple ("video/x-apple-video");
10679 case GST_MAKE_FOURCC ('H', '2', '6', '4'):
10680 case GST_MAKE_FOURCC ('a', 'v', 'c', '1'):
10681 _codec ("H.264 / AVC");
10682 caps = gst_caps_new_simple ("video/x-h264",
10683 "stream-format", G_TYPE_STRING, "avc",
10684 "alignment", G_TYPE_STRING, "au", NULL);
10686 case GST_MAKE_FOURCC ('a', 'v', 'c', '3'):
10687 _codec ("H.264 / AVC");
10688 caps = gst_caps_new_simple ("video/x-h264",
10689 "stream-format", G_TYPE_STRING, "avc3",
10690 "alignment", G_TYPE_STRING, "au", NULL);
10692 case GST_MAKE_FOURCC ('H', '2', '6', '5'):
10693 case GST_MAKE_FOURCC ('h', 'v', 'c', '1'):
10694 _codec ("H.265 / HEVC");
10695 caps = gst_caps_new_simple ("video/x-h265",
10696 "stream-format", G_TYPE_STRING, "hvc1",
10697 "alignment", G_TYPE_STRING, "au", NULL);
10699 case GST_MAKE_FOURCC ('h', 'e', 'v', '1'):
10700 _codec ("H.265 / HEVC");
10701 caps = gst_caps_new_simple ("video/x-h265",
10702 "stream-format", G_TYPE_STRING, "hev1",
10703 "alignment", G_TYPE_STRING, "au", NULL);
10705 case GST_MAKE_FOURCC ('r', 'l', 'e', ' '):
10706 _codec ("Run-length encoding");
10707 caps = gst_caps_new_simple ("video/x-rle",
10708 "layout", G_TYPE_STRING, "quicktime", NULL);
10710 case GST_MAKE_FOURCC ('W', 'R', 'L', 'E'):
10711 _codec ("Run-length encoding");
10712 caps = gst_caps_new_simple ("video/x-rle",
10713 "layout", G_TYPE_STRING, "microsoft", NULL);
10715 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
10716 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
10717 _codec ("Indeo Video 3");
10718 caps = gst_caps_new_simple ("video/x-indeo",
10719 "indeoversion", G_TYPE_INT, 3, NULL);
10721 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
10722 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
10723 _codec ("Intel Video 4");
10724 caps = gst_caps_new_simple ("video/x-indeo",
10725 "indeoversion", G_TYPE_INT, 4, NULL);
10727 case GST_MAKE_FOURCC ('d', 'v', 'c', 'p'):
10728 case GST_MAKE_FOURCC ('d', 'v', 'c', ' '):
10729 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
10730 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
10731 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
10732 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
10733 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
10734 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
10735 _codec ("DV Video");
10736 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
10737 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
10739 case GST_MAKE_FOURCC ('d', 'v', '5', 'n'): /* DVCPRO50 NTSC */
10740 case GST_MAKE_FOURCC ('d', 'v', '5', 'p'): /* DVCPRO50 PAL */
10741 _codec ("DVCPro50 Video");
10742 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
10743 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
10745 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
10746 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
10747 _codec ("DVCProHD Video");
10748 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
10749 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
10751 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
10752 _codec ("Apple Graphics (SMC)");
10753 caps = gst_caps_new_empty_simple ("video/x-smc");
10755 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
10757 caps = gst_caps_new_empty_simple ("video/x-vp3");
10759 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
10760 _codec ("VP6 Flash");
10761 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
10763 case GST_MAKE_FOURCC ('X', 'i', 'T', 'h'):
10765 caps = gst_caps_new_empty_simple ("video/x-theora");
10766 /* theora uses one byte of padding in the data stream because it does not
10767 * allow 0 sized packets while theora does */
10768 stream->padding = 1;
10770 case GST_MAKE_FOURCC ('d', 'r', 'a', 'c'):
10772 caps = gst_caps_new_empty_simple ("video/x-dirac");
10774 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
10775 _codec ("TIFF still images");
10776 caps = gst_caps_new_empty_simple ("image/tiff");
10778 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
10779 _codec ("Apple Intermediate Codec");
10780 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
10782 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
10783 _codec ("AVID DNxHD");
10784 caps = gst_caps_from_string ("video/x-dnxhd");
10786 case GST_MAKE_FOURCC ('V', 'P', '8', '0'):
10787 _codec ("On2 VP8");
10788 caps = gst_caps_from_string ("video/x-vp8");
10790 case GST_MAKE_FOURCC ('a', 'p', 'c', 's'):
10791 _codec ("Apple ProRes LT");
10793 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
10796 case GST_MAKE_FOURCC ('a', 'p', 'c', 'h'):
10797 _codec ("Apple ProRes HQ");
10799 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
10802 case GST_MAKE_FOURCC ('a', 'p', 'c', 'n'):
10803 _codec ("Apple ProRes");
10805 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
10808 case GST_MAKE_FOURCC ('a', 'p', 'c', 'o'):
10809 _codec ("Apple ProRes Proxy");
10811 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
10814 case GST_MAKE_FOURCC ('a', 'p', '4', 'h'):
10815 _codec ("Apple ProRes 4444");
10817 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
10822 caps = gst_caps_new_simple ("video/x-wmv",
10823 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
10825 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
10828 char *s, fourstr[5];
10830 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
10831 s = g_strdup_printf ("video/x-gst-fourcc-%s", g_strstrip (fourstr));
10832 caps = gst_caps_new_empty_simple (s);
10837 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
10840 gst_video_info_init (&info);
10841 gst_video_info_set_format (&info, format, stream->width, stream->height);
10842 caps = gst_video_info_to_caps (&info);
10843 *codec_name = gst_pb_utils_get_codec_description (caps);
10845 /* enable clipping for raw video streams */
10846 stream->need_clip = TRUE;
10853 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
10854 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
10857 const GstStructure *s;
10861 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
10864 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
10865 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
10866 _codec ("Raw 8-bit PCM audio");
10867 caps = gst_caps_new_simple ("audio/x-raw",
10868 "format", G_TYPE_STRING, "U8",
10869 "layout", G_TYPE_STRING, "interleaved", NULL);
10871 case GST_MAKE_FOURCC ('t', 'w', 'o', 's'):
10872 endian = G_BIG_ENDIAN;
10874 case GST_MAKE_FOURCC ('s', 'o', 'w', 't'):
10878 GstAudioFormat format;
10881 endian = G_LITTLE_ENDIAN;
10883 depth = stream->bytes_per_packet * 8;
10884 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
10886 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
10890 caps = gst_caps_new_simple ("audio/x-raw",
10891 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
10892 "layout", G_TYPE_STRING, "interleaved", NULL);
10895 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
10896 _codec ("Raw 64-bit floating-point audio");
10897 caps = gst_caps_new_simple ("audio/x-raw",
10898 "format", G_TYPE_STRING, "F64BE",
10899 "layout", G_TYPE_STRING, "interleaved", NULL);
10901 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
10902 _codec ("Raw 32-bit floating-point audio");
10903 caps = gst_caps_new_simple ("audio/x-raw",
10904 "format", G_TYPE_STRING, "F32BE",
10905 "layout", G_TYPE_STRING, "interleaved", NULL);
10908 _codec ("Raw 24-bit PCM audio");
10909 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
10911 caps = gst_caps_new_simple ("audio/x-raw",
10912 "format", G_TYPE_STRING, "S24BE",
10913 "layout", G_TYPE_STRING, "interleaved", NULL);
10915 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
10916 _codec ("Raw 32-bit PCM audio");
10917 caps = gst_caps_new_simple ("audio/x-raw",
10918 "format", G_TYPE_STRING, "S32BE",
10919 "layout", G_TYPE_STRING, "interleaved", NULL);
10921 case GST_MAKE_FOURCC ('u', 'l', 'a', 'w'):
10922 _codec ("Mu-law audio");
10923 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
10925 case GST_MAKE_FOURCC ('a', 'l', 'a', 'w'):
10926 _codec ("A-law audio");
10927 caps = gst_caps_new_empty_simple ("audio/x-alaw");
10931 _codec ("Microsoft ADPCM");
10932 /* Microsoft ADPCM-ACM code 2 */
10933 caps = gst_caps_new_simple ("audio/x-adpcm",
10934 "layout", G_TYPE_STRING, "microsoft", NULL);
10938 _codec ("DVI/IMA ADPCM");
10939 caps = gst_caps_new_simple ("audio/x-adpcm",
10940 "layout", G_TYPE_STRING, "dvi", NULL);
10944 _codec ("DVI/Intel IMA ADPCM");
10945 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
10946 caps = gst_caps_new_simple ("audio/x-adpcm",
10947 "layout", G_TYPE_STRING, "quicktime", NULL);
10951 /* MPEG layer 3, CBR only (pre QT4.1) */
10952 case GST_MAKE_FOURCC ('.', 'm', 'p', '3'):
10953 _codec ("MPEG-1 layer 3");
10954 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
10955 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
10956 "mpegversion", G_TYPE_INT, 1, NULL);
10959 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
10960 _codec ("EAC-3 audio");
10961 caps = gst_caps_new_simple ("audio/x-eac3",
10962 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
10963 stream->sampled = TRUE;
10965 case GST_MAKE_FOURCC ('a', 'c', '-', '3'):
10966 _codec ("AC-3 audio");
10967 caps = gst_caps_new_simple ("audio/x-ac3",
10968 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
10969 stream->sampled = TRUE;
10971 case GST_MAKE_FOURCC ('M', 'A', 'C', '3'):
10973 caps = gst_caps_new_simple ("audio/x-mace",
10974 "maceversion", G_TYPE_INT, 3, NULL);
10976 case GST_MAKE_FOURCC ('M', 'A', 'C', '6'):
10978 caps = gst_caps_new_simple ("audio/x-mace",
10979 "maceversion", G_TYPE_INT, 6, NULL);
10981 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
10983 caps = gst_caps_new_empty_simple ("application/ogg");
10985 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
10986 _codec ("DV audio");
10987 caps = gst_caps_new_empty_simple ("audio/x-dv");
10989 case GST_MAKE_FOURCC ('m', 'p', '4', 'a'):
10990 _codec ("MPEG-4 AAC audio");
10991 caps = gst_caps_new_simple ("audio/mpeg",
10992 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
10993 "stream-format", G_TYPE_STRING, "raw", NULL);
10995 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
10996 _codec ("QDesign Music");
10997 caps = gst_caps_new_empty_simple ("audio/x-qdm");
10999 case GST_MAKE_FOURCC ('Q', 'D', 'M', '2'):
11000 _codec ("QDesign Music v.2");
11001 /* FIXME: QDesign music version 2 (no constant) */
11002 if (FALSE && data) {
11003 caps = gst_caps_new_simple ("audio/x-qdm2",
11004 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
11005 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
11006 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
11008 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
11011 case GST_MAKE_FOURCC ('a', 'g', 's', 'm'):
11012 _codec ("GSM audio");
11013 caps = gst_caps_new_empty_simple ("audio/x-gsm");
11015 case GST_MAKE_FOURCC ('s', 'a', 'm', 'r'):
11016 _codec ("AMR audio");
11017 caps = gst_caps_new_empty_simple ("audio/AMR");
11019 case GST_MAKE_FOURCC ('s', 'a', 'w', 'b'):
11020 _codec ("AMR-WB audio");
11021 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
11023 case GST_MAKE_FOURCC ('i', 'm', 'a', '4'):
11024 _codec ("Quicktime IMA ADPCM");
11025 caps = gst_caps_new_simple ("audio/x-adpcm",
11026 "layout", G_TYPE_STRING, "quicktime", NULL);
11028 case GST_MAKE_FOURCC ('a', 'l', 'a', 'c'):
11029 _codec ("Apple lossless audio");
11030 caps = gst_caps_new_empty_simple ("audio/x-alac");
11032 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
11033 _codec ("QualComm PureVoice");
11034 caps = gst_caps_from_string ("audio/qcelp");
11038 caps = gst_caps_new_empty_simple ("audio/x-wma");
11040 case GST_MAKE_FOURCC ('l', 'p', 'c', 'm'):
11045 GstAudioFormat format;
11048 FLAG_IS_FLOAT = 0x1,
11049 FLAG_IS_BIG_ENDIAN = 0x2,
11050 FLAG_IS_SIGNED = 0x4,
11051 FLAG_IS_PACKED = 0x8,
11052 FLAG_IS_ALIGNED_HIGH = 0x10,
11053 FLAG_IS_NON_INTERLEAVED = 0x20
11055 _codec ("Raw LPCM audio");
11057 if (data && len >= 56) {
11058 depth = QT_UINT32 (data + 40);
11059 flags = QT_UINT32 (data + 44);
11060 width = QT_UINT32 (data + 48) * 8 / stream->n_channels;
11062 if ((flags & FLAG_IS_FLOAT) == 0) {
11067 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
11068 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
11069 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
11070 caps = gst_caps_new_simple ("audio/x-raw",
11071 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
11072 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
11073 "non-interleaved" : "interleaved", NULL);
11080 if (flags & FLAG_IS_BIG_ENDIAN)
11081 format = GST_AUDIO_FORMAT_F64BE;
11083 format = GST_AUDIO_FORMAT_F64LE;
11085 if (flags & FLAG_IS_BIG_ENDIAN)
11086 format = GST_AUDIO_FORMAT_F32BE;
11088 format = GST_AUDIO_FORMAT_F32LE;
11090 caps = gst_caps_new_simple ("audio/x-raw",
11091 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
11092 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
11093 "non-interleaved" : "interleaved", NULL);
11097 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
11101 char *s, fourstr[5];
11103 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11104 s = g_strdup_printf ("audio/x-gst-fourcc-%s", g_strstrip (fourstr));
11105 caps = gst_caps_new_empty_simple (s);
11111 GstCaps *templ_caps =
11112 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
11113 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
11114 gst_caps_unref (caps);
11115 gst_caps_unref (templ_caps);
11116 caps = intersection;
11119 /* enable clipping for raw audio streams */
11120 s = gst_caps_get_structure (caps, 0);
11121 name = gst_structure_get_name (s);
11122 if (g_str_has_prefix (name, "audio/x-raw")) {
11123 stream->need_clip = TRUE;
11124 stream->max_buffer_size = 4096 * stream->bytes_per_frame;
11125 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
11131 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
11132 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
11136 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
11139 case GST_MAKE_FOURCC ('m', 'p', '4', 's'):
11140 _codec ("DVD subtitle");
11141 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
11142 stream->need_process = TRUE;
11144 case GST_MAKE_FOURCC ('t', 'e', 'x', 't'):
11145 _codec ("Quicktime timed text");
11147 case GST_MAKE_FOURCC ('t', 'x', '3', 'g'):
11148 _codec ("3GPP timed text");
11150 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
11152 /* actual text piece needs to be extracted */
11153 stream->need_process = TRUE;
11157 char *s, fourstr[5];
11159 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11160 s = g_strdup_printf ("text/x-gst-fourcc-%s", g_strstrip (fourstr));
11161 caps = gst_caps_new_empty_simple (s);
11169 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
11170 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
11175 case GST_MAKE_FOURCC ('m', '1', 'v', ' '):
11176 _codec ("MPEG 1 video");
11177 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
11178 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);