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 /* quicktime segments */
299 QtDemuxSegment *segments;
304 GstTagList *pending_tags;
305 gboolean send_global_tags;
307 GstEvent *pending_event;
317 gboolean chunks_are_samples; /* TRUE means treat chunks as samples */
321 GstByteReader co_chunk;
323 guint32 current_chunk;
325 guint32 samples_per_chunk;
326 guint32 stco_sample_index;
328 guint32 sample_size; /* 0 means variable sizes are stored in stsz */
331 guint32 n_samples_per_chunk;
332 guint32 stsc_chunk_index;
333 guint32 stsc_sample_index;
334 guint64 chunk_offset;
337 guint32 stts_samples;
338 guint32 n_sample_times;
339 guint32 stts_sample_index;
341 guint32 stts_duration;
343 gboolean stss_present;
344 guint32 n_sample_syncs;
347 gboolean stps_present;
348 guint32 n_sample_partial_syncs;
351 gboolean ctts_present;
352 guint32 n_composition_times;
354 guint32 ctts_sample_index;
359 gboolean parsed_trex;
360 guint32 def_sample_duration;
361 guint32 def_sample_size;
362 guint32 def_sample_flags;
369 QTDEMUX_STATE_INITIAL, /* Initial state (haven't got the header yet) */
370 QTDEMUX_STATE_HEADER, /* Parsing the header */
371 QTDEMUX_STATE_MOVIE, /* Parsing/Playing the media data */
372 QTDEMUX_STATE_BUFFER_MDAT /* Buffering the mdat atom */
375 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
376 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
377 guint32 fourcc, GstByteReader * parser);
378 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
379 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
380 guint32 fourcc, GstByteReader * parser);
382 static GstStaticPadTemplate gst_qtdemux_sink_template =
383 GST_STATIC_PAD_TEMPLATE ("sink",
386 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
390 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
391 GST_STATIC_PAD_TEMPLATE ("video_%u",
394 GST_STATIC_CAPS_ANY);
396 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
397 GST_STATIC_PAD_TEMPLATE ("audio_%u",
400 GST_STATIC_CAPS_ANY);
402 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
403 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
406 GST_STATIC_CAPS_ANY);
408 #define gst_qtdemux_parent_class parent_class
409 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
411 static void gst_qtdemux_dispose (GObject * object);
414 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
417 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
418 QtDemuxStream * str, gint64 media_offset);
421 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
422 static GstIndex *gst_qtdemux_get_index (GstElement * element);
424 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
425 GstStateChange transition);
426 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
427 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
428 GstObject * parent, GstPadMode mode, gboolean active);
430 static void gst_qtdemux_loop (GstPad * pad);
431 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
433 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
435 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
436 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
437 QtDemuxStream * stream);
438 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
441 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
442 const guint8 * buffer, guint length);
443 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
444 const guint8 * buffer, guint length);
445 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
447 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
448 QtDemuxStream * stream, GNode * esds, GstTagList * list);
449 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
450 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
451 gchar ** codec_name);
452 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
453 QtDemuxStream * stream, guint32 fourcc, const guint8 * data, int len,
454 gchar ** codec_name);
455 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux,
456 QtDemuxStream * stream, guint32 fourcc, const guint8 * data,
457 gchar ** codec_name);
458 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
459 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
460 gchar ** codec_name);
462 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
463 QtDemuxStream * stream, guint32 n);
464 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
465 static void gst_qtdemux_stream_free (GstQTDemux * qtdemux,
466 QtDemuxStream * stream);
467 static void gst_qtdemux_stream_clear (GstQTDemux * qtdemux,
468 QtDemuxStream * stream);
469 static void gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int index);
470 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
471 static void qtdemux_do_allocation (GstQTDemux * qtdemux,
472 QtDemuxStream * stream);
475 gst_qtdemux_class_init (GstQTDemuxClass * klass)
477 GObjectClass *gobject_class;
478 GstElementClass *gstelement_class;
480 gobject_class = (GObjectClass *) klass;
481 gstelement_class = (GstElementClass *) klass;
483 parent_class = g_type_class_peek_parent (klass);
485 gobject_class->dispose = gst_qtdemux_dispose;
487 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
489 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
490 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
493 gst_tag_register_musicbrainz_tags ();
495 gst_element_class_add_pad_template (gstelement_class,
496 gst_static_pad_template_get (&gst_qtdemux_sink_template));
497 gst_element_class_add_pad_template (gstelement_class,
498 gst_static_pad_template_get (&gst_qtdemux_videosrc_template));
499 gst_element_class_add_pad_template (gstelement_class,
500 gst_static_pad_template_get (&gst_qtdemux_audiosrc_template));
501 gst_element_class_add_pad_template (gstelement_class,
502 gst_static_pad_template_get (&gst_qtdemux_subsrc_template));
503 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
505 "Demultiplex a QuickTime file into audio and video streams",
506 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
508 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
513 gst_qtdemux_init (GstQTDemux * qtdemux)
516 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
517 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
518 gst_pad_set_activatemode_function (qtdemux->sinkpad,
519 qtdemux_sink_activate_mode);
520 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
521 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
522 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
524 qtdemux->state = QTDEMUX_STATE_INITIAL;
525 qtdemux->pullbased = FALSE;
526 qtdemux->posted_redirect = FALSE;
527 qtdemux->neededbytes = 16;
529 qtdemux->adapter = gst_adapter_new ();
531 qtdemux->first_mdat = -1;
532 qtdemux->got_moov = FALSE;
533 qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
534 qtdemux->mdatbuffer = NULL;
535 qtdemux->restoredata_buffer = NULL;
536 qtdemux->restoredata_offset = GST_CLOCK_TIME_NONE;
537 qtdemux->fragment_start = -1;
538 qtdemux->fragment_start_offset = -1;
539 qtdemux->media_caps = NULL;
540 qtdemux->exposed = FALSE;
541 qtdemux->mss_mode = FALSE;
542 qtdemux->pending_newsegment = NULL;
543 qtdemux->upstream_newsegment = FALSE;
544 qtdemux->have_group_id = FALSE;
545 qtdemux->group_id = G_MAXUINT;
546 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
547 qtdemux->flowcombiner = gst_flow_combiner_new ();
549 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
553 gst_qtdemux_dispose (GObject * object)
555 GstQTDemux *qtdemux = GST_QTDEMUX (object);
557 if (qtdemux->adapter) {
558 g_object_unref (G_OBJECT (qtdemux->adapter));
559 qtdemux->adapter = NULL;
561 gst_flow_combiner_free (qtdemux->flowcombiner);
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->sent_eos = FALSE;
1401 stream->segment_seqnum = seqnum;
1403 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1404 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1406 segment->position = desired_offset;
1407 segment->time = desired_offset;
1408 qtdemux->segment_base = desired_offset;
1410 /* we stop at the end */
1411 if (segment->stop == -1)
1412 segment->stop = segment->duration;
1417 /* do a seek in pull based mode */
1419 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1424 GstSeekType cur_type, stop_type;
1428 GstSegment seeksegment;
1430 GstEvent *flush_event;
1433 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1435 gst_event_parse_seek (event, &rate, &format, &flags,
1436 &cur_type, &cur, &stop_type, &stop);
1437 seqnum = gst_event_get_seqnum (event);
1439 /* we have to have a format as the segment format. Try to convert
1441 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1445 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1447 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1451 flush = flags & GST_SEEK_FLAG_FLUSH;
1453 /* stop streaming, either by flushing or by pausing the task */
1455 flush_event = gst_event_new_flush_start ();
1457 gst_event_set_seqnum (flush_event, seqnum);
1458 /* unlock upstream pull_range */
1459 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1460 /* make sure out loop function exits */
1461 gst_qtdemux_push_event (qtdemux, flush_event);
1463 /* non flushing seek, pause the task */
1464 gst_pad_pause_task (qtdemux->sinkpad);
1467 /* wait for streaming to finish */
1468 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1470 /* copy segment, we need this because we still need the old
1471 * segment when we close the current segment. */
1472 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1475 /* configure the segment with the seek variables */
1476 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1477 gst_segment_do_seek (&seeksegment, rate, format, flags,
1478 cur_type, cur, stop_type, stop, &update);
1481 /* now do the seek, this actually never returns FALSE */
1482 gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum);
1484 /* prepare for streaming again */
1486 flush_event = gst_event_new_flush_stop (TRUE);
1488 gst_event_set_seqnum (flush_event, seqnum);
1490 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1491 gst_qtdemux_push_event (qtdemux, flush_event);
1494 /* commit the new segment */
1495 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1497 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1498 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1499 qtdemux->segment.format, qtdemux->segment.position);
1501 gst_message_set_seqnum (msg, seqnum);
1502 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1505 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1506 qtdemux->sinkpad, NULL);
1508 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1515 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1521 qtdemux_ensure_index (GstQTDemux * qtdemux)
1525 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1527 /* Build complete index */
1528 for (i = 0; i < qtdemux->n_streams; i++) {
1529 QtDemuxStream *stream = qtdemux->streams[i];
1531 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1539 GST_LOG_OBJECT (qtdemux,
1540 "Building complete index of stream %u for seeking failed!", i);
1546 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1549 gboolean res = TRUE;
1550 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1552 switch (GST_EVENT_TYPE (event)) {
1553 case GST_EVENT_SEEK:
1555 #ifndef GST_DISABLE_GST_DEBUG
1556 GstClockTime ts = gst_util_get_timestamp ();
1559 if (qtdemux->upstream_newsegment && qtdemux->fragmented) {
1560 /* seek should be handled by upstream, we might need to re-download fragments */
1561 GST_DEBUG_OBJECT (qtdemux,
1562 "let upstream handle seek for fragmented playback");
1566 /* Build complete index for seeking;
1567 * if not a fragmented file at least */
1568 if (!qtdemux->fragmented)
1569 if (!qtdemux_ensure_index (qtdemux))
1571 #ifndef GST_DISABLE_GST_DEBUG
1572 ts = gst_util_get_timestamp () - ts;
1573 GST_INFO_OBJECT (qtdemux,
1574 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1577 if (qtdemux->pullbased) {
1578 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1579 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1580 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1582 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams
1583 && !qtdemux->fragmented) {
1584 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1586 GST_DEBUG_OBJECT (qtdemux,
1587 "ignoring seek in push mode in current state");
1590 gst_event_unref (event);
1593 case GST_EVENT_NAVIGATION:
1595 gst_event_unref (event);
1599 res = gst_pad_event_default (pad, parent, event);
1609 GST_ERROR_OBJECT (qtdemux, "Index failed");
1610 gst_event_unref (event);
1616 /* stream/index return sample that is min/max w.r.t. byte position,
1617 * time is min/max w.r.t. time of samples,
1618 * the latter need not be time of the former sample */
1620 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1621 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1624 gint64 time, min_time;
1625 QtDemuxStream *stream;
1631 for (n = 0; n < qtdemux->n_streams; ++n) {
1634 gboolean set_sample;
1636 str = qtdemux->streams[n];
1643 i = str->n_samples - 1;
1647 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1648 if (str->samples[i].size == 0)
1651 if (fw && (str->samples[i].offset < byte_pos))
1654 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1657 /* move stream to first available sample */
1659 gst_qtdemux_move_stream (qtdemux, str, i);
1663 /* avoid index from sparse streams since they might be far away */
1665 /* determine min/max time */
1666 time = str->samples[i].timestamp + str->samples[i].pts_offset;
1667 time = gst_util_uint64_scale (time, GST_SECOND, str->timescale);
1668 if (min_time == -1 || (!fw && time > min_time) ||
1669 (fw && time < min_time)) {
1673 /* determine stream with leading sample, to get its position */
1675 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1676 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1684 /* no sample for this stream, mark eos */
1686 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1697 static QtDemuxStream *
1698 _create_stream (void)
1700 QtDemuxStream *stream;
1702 stream = g_new0 (QtDemuxStream, 1);
1703 /* new streams always need a discont */
1704 stream->discont = TRUE;
1705 /* we enable clipping for raw audio/video streams */
1706 stream->need_clip = FALSE;
1707 stream->need_process = FALSE;
1708 stream->segment_index = -1;
1709 stream->time_position = 0;
1710 stream->sample_index = -1;
1711 stream->offset_in_sample = 0;
1712 stream->new_stream = TRUE;
1717 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1719 GstStructure *structure;
1720 const gchar *variant;
1721 const GstCaps *mediacaps = NULL;
1723 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1725 structure = gst_caps_get_structure (caps, 0);
1726 variant = gst_structure_get_string (structure, "variant");
1728 if (variant && strcmp (variant, "mss-fragmented") == 0) {
1729 QtDemuxStream *stream;
1730 const GValue *value;
1732 demux->fragmented = TRUE;
1733 demux->mss_mode = TRUE;
1735 if (demux->n_streams > 1) {
1736 /* can't do this, we can only renegotiate for another mss format */
1740 value = gst_structure_get_value (structure, "media-caps");
1743 const GValue *timescale_v;
1745 /* TODO update when stream changes during playback */
1747 if (demux->n_streams == 0) {
1748 stream = _create_stream ();
1749 demux->streams[demux->n_streams] = stream;
1750 demux->n_streams = 1;
1752 stream = demux->streams[0];
1755 timescale_v = gst_structure_get_value (structure, "timescale");
1757 stream->timescale = g_value_get_uint64 (timescale_v);
1759 /* default mss timescale */
1760 stream->timescale = 10000000;
1762 demux->timescale = stream->timescale;
1764 mediacaps = gst_value_get_caps (value);
1765 if (!stream->caps || !gst_caps_is_equal_fixed (mediacaps, stream->caps)) {
1766 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1768 stream->new_caps = TRUE;
1770 gst_caps_replace (&stream->caps, (GstCaps *) mediacaps);
1771 structure = gst_caps_get_structure (mediacaps, 0);
1772 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
1773 stream->subtype = FOURCC_vide;
1775 gst_structure_get_int (structure, "width", &stream->width);
1776 gst_structure_get_int (structure, "height", &stream->height);
1777 gst_structure_get_fraction (structure, "framerate", &stream->fps_n,
1779 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
1781 stream->subtype = FOURCC_soun;
1782 gst_structure_get_int (structure, "channels", &stream->n_channels);
1783 gst_structure_get_int (structure, "rate", &rate);
1784 stream->rate = rate;
1787 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
1789 demux->mss_mode = FALSE;
1796 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
1800 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
1801 gst_pad_stop_task (qtdemux->sinkpad);
1803 if (hard || qtdemux->upstream_newsegment) {
1804 qtdemux->state = QTDEMUX_STATE_INITIAL;
1805 qtdemux->neededbytes = 16;
1806 qtdemux->todrop = 0;
1807 qtdemux->pullbased = FALSE;
1808 qtdemux->posted_redirect = FALSE;
1809 qtdemux->first_mdat = -1;
1810 qtdemux->header_size = 0;
1811 qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
1812 qtdemux->restoredata_offset = GST_CLOCK_TIME_NONE;
1813 if (qtdemux->mdatbuffer)
1814 gst_buffer_unref (qtdemux->mdatbuffer);
1815 if (qtdemux->restoredata_buffer)
1816 gst_buffer_unref (qtdemux->restoredata_buffer);
1817 qtdemux->mdatbuffer = NULL;
1818 qtdemux->restoredata_buffer = NULL;
1819 qtdemux->mdatleft = 0;
1820 if (qtdemux->comp_brands)
1821 gst_buffer_unref (qtdemux->comp_brands);
1822 qtdemux->comp_brands = NULL;
1823 qtdemux->last_moov_offset = -1;
1824 if (qtdemux->moov_node)
1825 g_node_destroy (qtdemux->moov_node);
1826 qtdemux->moov_node = NULL;
1827 qtdemux->moov_node_compressed = NULL;
1828 if (qtdemux->tag_list)
1829 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
1830 qtdemux->tag_list = NULL;
1832 if (qtdemux->element_index)
1833 gst_object_unref (qtdemux->element_index);
1834 qtdemux->element_index = NULL;
1836 qtdemux->major_brand = 0;
1837 if (qtdemux->pending_newsegment)
1838 gst_event_unref (qtdemux->pending_newsegment);
1839 qtdemux->pending_newsegment = NULL;
1840 qtdemux->upstream_newsegment = FALSE;
1841 qtdemux->upstream_seekable = FALSE;
1842 qtdemux->upstream_size = 0;
1844 qtdemux->fragment_start = -1;
1845 qtdemux->fragment_start_offset = -1;
1846 qtdemux->duration = 0;
1847 qtdemux->mfra_offset = 0;
1848 qtdemux->moof_offset = 0;
1849 qtdemux->chapters_track_id = 0;
1850 qtdemux->have_group_id = FALSE;
1851 qtdemux->group_id = G_MAXUINT;
1853 qtdemux->offset = 0;
1854 gst_adapter_clear (qtdemux->adapter);
1855 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
1856 qtdemux->segment_base = 0;
1859 for (n = 0; n < qtdemux->n_streams; n++) {
1860 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
1861 qtdemux->streams[n] = NULL;
1863 qtdemux->n_streams = 0;
1864 qtdemux->n_video_streams = 0;
1865 qtdemux->n_audio_streams = 0;
1866 qtdemux->n_sub_streams = 0;
1867 qtdemux->exposed = FALSE;
1868 qtdemux->fragmented = FALSE;
1869 qtdemux->mss_mode = FALSE;
1870 gst_caps_replace (&qtdemux->media_caps, NULL);
1871 qtdemux->timescale = 0;
1872 qtdemux->got_moov = FALSE;
1873 } else if (qtdemux->mss_mode) {
1874 for (n = 0; n < qtdemux->n_streams; n++)
1875 gst_qtdemux_stream_clear (qtdemux, qtdemux->streams[n]);
1877 for (n = 0; n < qtdemux->n_streams; n++) {
1878 qtdemux->streams[n]->sent_eos = FALSE;
1879 qtdemux->streams[n]->segment_seqnum = 0;
1880 qtdemux->streams[n]->time_position = 0;
1886 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
1889 GstQTDemux *demux = GST_QTDEMUX (parent);
1890 gboolean res = TRUE;
1892 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
1894 switch (GST_EVENT_TYPE (event)) {
1895 case GST_EVENT_SEGMENT:
1898 QtDemuxStream *stream;
1901 GstEvent *segment_event;
1903 /* some debug output */
1904 gst_event_copy_segment (event, &segment);
1905 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
1908 if (segment.format == GST_FORMAT_TIME) {
1909 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
1910 gst_event_replace (&demux->pending_newsegment, event);
1911 demux->upstream_newsegment = TRUE;
1913 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
1914 "not in time format");
1916 /* chain will send initial newsegment after pads have been added */
1917 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
1918 GST_DEBUG_OBJECT (demux, "still starting, eating event");
1923 /* check if this matches a time seek we received previously
1924 * FIXME for backwards compatibility reasons we use the
1925 * seek_offset here to compare. In the future we might want to
1926 * change this to use the seqnum as it uniquely should identify
1927 * the segment that corresponds to the seek. */
1928 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
1929 ", received segment offset %" G_GINT64_FORMAT,
1930 demux->seek_offset, segment.start);
1931 if (segment.format == GST_FORMAT_BYTES
1932 && demux->seek_offset == segment.start) {
1933 GST_OBJECT_LOCK (demux);
1934 offset = segment.start;
1936 segment.format = GST_FORMAT_TIME;
1937 segment.start = demux->push_seek_start;
1938 segment.stop = demux->push_seek_stop;
1939 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
1940 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
1941 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
1942 GST_OBJECT_UNLOCK (demux);
1945 /* we only expect a BYTE segment, e.g. following a seek */
1946 if (segment.format == GST_FORMAT_BYTES) {
1947 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
1948 offset = segment.start;
1950 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
1951 NULL, (gint64 *) & segment.start);
1952 if ((gint64) segment.start < 0)
1955 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
1956 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
1957 NULL, (gint64 *) & segment.stop);
1958 /* keyframe seeking should already arrange for start >= stop,
1959 * but make sure in other rare cases */
1960 segment.stop = MAX (segment.stop, segment.start);
1962 } else if (segment.format == GST_FORMAT_TIME) {
1965 gst_qtdemux_push_event (demux, gst_event_ref (event));
1966 gst_event_new_new_segment_full (segment.update, segment.rate,
1967 segment.arate, GST_FORMAT_TIME, segment.start, segment.stop,
1969 gst_adapter_clear (demux->adapter);
1970 demux->neededbytes = 16;
1974 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
1978 /* accept upstream's notion of segment and distribute along */
1979 segment.format = GST_FORMAT_TIME;
1980 segment.position = segment.time = segment.start;
1981 segment.duration = demux->segment.duration;
1982 segment.base = gst_segment_to_running_time (&demux->segment,
1983 GST_FORMAT_TIME, demux->segment.position);
1985 gst_segment_copy_into (&segment, &demux->segment);
1986 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
1987 segment_event = gst_event_new_segment (&segment);
1988 gst_event_set_seqnum (segment_event, gst_event_get_seqnum (event));
1989 gst_qtdemux_push_event (demux, segment_event);
1991 /* clear leftover in current segment, if any */
1992 gst_adapter_clear (demux->adapter);
1993 /* set up streaming thread */
1994 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx, NULL);
1995 demux->offset = offset;
1997 demux->todrop = stream->samples[idx].offset - offset;
1998 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2000 /* set up for EOS */
2001 if (demux->upstream_newsegment) {
2002 demux->neededbytes = 16;
2004 demux->neededbytes = -1;
2009 gst_event_unref (event);
2014 case GST_EVENT_FLUSH_STOP:
2018 dur = demux->segment.duration;
2019 gst_qtdemux_reset (demux, FALSE);
2020 demux->segment.duration = dur;
2024 /* If we are in push mode, and get an EOS before we've seen any streams,
2025 * then error out - we have nowhere to send the EOS */
2026 if (!demux->pullbased) {
2028 gboolean has_valid_stream = FALSE;
2029 for (i = 0; i < demux->n_streams; i++) {
2030 if (demux->streams[i]->pad != NULL) {
2031 has_valid_stream = TRUE;
2035 if (!has_valid_stream)
2036 gst_qtdemux_post_no_playable_stream_error (demux);
2038 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2039 (guint) gst_adapter_available (demux->adapter));
2040 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2046 case GST_EVENT_CAPS:{
2047 GstCaps *caps = NULL;
2049 gst_event_parse_caps (event, &caps);
2050 gst_qtdemux_setcaps (demux, caps);
2052 gst_event_unref (event);
2060 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2068 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2070 GstQTDemux *demux = GST_QTDEMUX (element);
2072 GST_OBJECT_LOCK (demux);
2073 if (demux->element_index)
2074 gst_object_unref (demux->element_index);
2076 demux->element_index = gst_object_ref (index);
2078 demux->element_index = NULL;
2080 GST_OBJECT_UNLOCK (demux);
2081 /* object lock might be taken again */
2083 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2084 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2085 demux->element_index, demux->index_id);
2089 gst_qtdemux_get_index (GstElement * element)
2091 GstIndex *result = NULL;
2092 GstQTDemux *demux = GST_QTDEMUX (element);
2094 GST_OBJECT_LOCK (demux);
2095 if (demux->element_index)
2096 result = gst_object_ref (demux->element_index);
2097 GST_OBJECT_UNLOCK (demux);
2099 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2106 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2108 g_free ((gpointer) stream->stco.data);
2109 stream->stco.data = NULL;
2110 g_free ((gpointer) stream->stsz.data);
2111 stream->stsz.data = NULL;
2112 g_free ((gpointer) stream->stsc.data);
2113 stream->stsc.data = NULL;
2114 g_free ((gpointer) stream->stts.data);
2115 stream->stts.data = NULL;
2116 g_free ((gpointer) stream->stss.data);
2117 stream->stss.data = NULL;
2118 g_free ((gpointer) stream->stps.data);
2119 stream->stps.data = NULL;
2120 g_free ((gpointer) stream->ctts.data);
2121 stream->ctts.data = NULL;
2125 gst_qtdemux_stream_clear (GstQTDemux * qtdemux, QtDemuxStream * stream)
2127 if (stream->allocator)
2128 gst_object_unref (stream->allocator);
2129 while (stream->buffers) {
2130 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2131 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2133 if (stream->rgb8_palette) {
2134 gst_memory_unref (stream->rgb8_palette);
2135 stream->rgb8_palette = NULL;
2137 g_free (stream->samples);
2138 stream->samples = NULL;
2139 g_free (stream->segments);
2140 stream->segments = NULL;
2141 if (stream->pending_tags)
2142 gst_tag_list_unref (stream->pending_tags);
2143 stream->pending_tags = NULL;
2144 g_free (stream->redirect_uri);
2145 stream->redirect_uri = NULL;
2146 /* free stbl sub-atoms */
2147 gst_qtdemux_stbl_free (stream);
2149 stream->sent_eos = FALSE;
2150 stream->segment_index = -1;
2151 stream->time_position = 0;
2152 stream->sample_index = -1;
2153 stream->stbl_index = -1;
2154 stream->n_samples = 0;
2155 stream->sparse = FALSE;
2159 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
2161 gst_qtdemux_stream_clear (qtdemux, stream);
2163 gst_caps_unref (stream->caps);
2164 stream->caps = NULL;
2166 gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
2167 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, stream->pad);
2173 gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int i)
2175 g_assert (i >= 0 && i < qtdemux->n_streams && qtdemux->streams[i] != NULL);
2177 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[i]);
2178 qtdemux->streams[i] = qtdemux->streams[qtdemux->n_streams - 1];
2179 qtdemux->streams[qtdemux->n_streams - 1] = NULL;
2180 qtdemux->n_streams--;
2183 static GstStateChangeReturn
2184 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2186 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2187 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2189 switch (transition) {
2190 case GST_STATE_CHANGE_PAUSED_TO_READY:
2196 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2198 switch (transition) {
2199 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2200 gst_qtdemux_reset (qtdemux, TRUE);
2211 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2213 /* counts as header data */
2214 qtdemux->header_size += length;
2216 /* only consider at least a sufficiently complete ftyp atom */
2220 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2221 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2222 GST_FOURCC_ARGS (qtdemux->major_brand));
2223 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2224 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2229 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist)
2231 /* Strip out bogus fields */
2233 gst_tag_list_remove_tag (taglist, GST_TAG_VIDEO_CODEC);
2235 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, taglist);
2237 if (qtdemux->tag_list) {
2238 /* prioritize native tags using _KEEP mode */
2239 gst_tag_list_insert (qtdemux->tag_list, taglist, GST_TAG_MERGE_KEEP);
2240 gst_tag_list_unref (taglist);
2242 qtdemux->tag_list = taglist;
2247 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2249 static guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2250 0x97, 0xA9, 0x42, 0xE8,
2251 0x9C, 0x71, 0x99, 0x94,
2252 0x91, 0xE3, 0xAF, 0xAC
2254 static guint8 playready_uuid[] = {
2255 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2256 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2260 /* counts as header data */
2261 qtdemux->header_size += length;
2263 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2265 if (length <= offset + 16) {
2266 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2270 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2272 GstTagList *taglist;
2274 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2275 length - offset - 16, NULL);
2276 taglist = gst_tag_list_from_xmp_buffer (buf);
2277 gst_buffer_unref (buf);
2279 qtdemux_handle_xmp_taglist (qtdemux, taglist);
2281 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
2283 const gunichar2 *s_utf16;
2286 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
2287 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
2288 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
2289 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
2293 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
2294 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
2297 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
2298 GST_READ_UINT32_LE (buffer + offset),
2299 GST_READ_UINT32_LE (buffer + offset + 4),
2300 GST_READ_UINT32_LE (buffer + offset + 8),
2301 GST_READ_UINT32_LE (buffer + offset + 12));
2305 /* caller verifies at least 8 bytes in buf */
2307 extract_initial_length_and_fourcc (const guint8 * data, guint size,
2308 guint64 * plength, guint32 * pfourcc)
2313 length = QT_UINT32 (data);
2314 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2315 fourcc = QT_FOURCC (data + 4);
2316 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
2319 length = G_MAXUINT32;
2320 } else if (length == 1 && size >= 16) {
2321 /* this means we have an extended size, which is the 64 bit value of
2322 * the next 8 bytes */
2323 length = QT_UINT64 (data + 8);
2324 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2334 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
2336 guint32 version = 0;
2337 guint64 duration = 0;
2339 if (!gst_byte_reader_get_uint32_be (br, &version))
2344 if (!gst_byte_reader_get_uint64_be (br, &duration))
2349 if (!gst_byte_reader_get_uint32_be (br, &dur))
2354 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
2355 qtdemux->duration = duration;
2361 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
2367 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
2368 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
2370 if (!stream->parsed_trex && qtdemux->moov_node) {
2372 GstByteReader trex_data;
2374 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
2376 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
2379 guint32 id = 0, dur = 0, size = 0, flags = 0, dummy = 0;
2381 /* skip version/flags */
2382 if (!gst_byte_reader_skip (&trex_data, 4))
2384 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
2386 if (id != stream->track_id)
2388 /* sample description index; ignore */
2389 if (!gst_byte_reader_get_uint32_be (&trex_data, &dummy))
2391 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2393 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
2395 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
2398 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
2399 "duration %d, size %d, flags 0x%x", stream->track_id,
2402 stream->parsed_trex = TRUE;
2403 stream->def_sample_duration = dur;
2404 stream->def_sample_size = size;
2405 stream->def_sample_flags = flags;
2408 /* iterate all siblings */
2409 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
2415 *ds_duration = stream->def_sample_duration;
2416 *ds_size = stream->def_sample_size;
2417 *ds_flags = stream->def_sample_flags;
2419 /* even then, above values are better than random ... */
2420 if (G_UNLIKELY (!stream->parsed_trex)) {
2421 GST_WARNING_OBJECT (qtdemux,
2422 "failed to find fragment defaults for stream %d", stream->track_id);
2430 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
2431 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
2432 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
2433 gint64 * base_offset, gint64 * running_offset)
2436 gint32 data_offset = 0;
2437 guint32 flags = 0, first_flags = 0, samples_count = 0;
2440 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
2441 QtDemuxSample *sample;
2442 gboolean ismv = FALSE;
2444 GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
2445 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT,
2446 stream->track_id, d_sample_duration, d_sample_size, d_sample_flags,
2449 /* presence of stss or not can't really tell us much,
2450 * and flags and so on tend to be marginally reliable in these files */
2451 if (stream->subtype == FOURCC_soun) {
2452 GST_DEBUG_OBJECT (qtdemux,
2453 "sound track in fragmented file; marking all keyframes");
2454 stream->all_keyframe = TRUE;
2457 if (!gst_byte_reader_skip (trun, 1) ||
2458 !gst_byte_reader_get_uint24_be (trun, &flags))
2461 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
2464 if (flags & TR_DATA_OFFSET) {
2465 /* note this is really signed */
2466 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
2468 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
2469 /* default base offset = first byte of moof */
2470 if (*base_offset == -1) {
2471 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
2472 *base_offset = moof_offset;
2474 *running_offset = *base_offset + data_offset;
2476 /* if no offset at all, that would mean data starts at moof start,
2477 * which is a bit wrong and is ismv crappy way, so compensate
2478 * assuming data is in mdat following moof */
2479 if (*base_offset == -1) {
2480 *base_offset = moof_offset + moof_length + 8;
2481 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
2484 if (*running_offset == -1)
2485 *running_offset = *base_offset;
2488 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
2490 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
2491 data_offset, flags, samples_count);
2493 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2494 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
2495 GST_DEBUG_OBJECT (qtdemux,
2496 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
2497 flags ^= TR_FIRST_SAMPLE_FLAGS;
2499 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
2501 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
2505 /* FIXME ? spec says other bits should also be checked to determine
2506 * entry size (and prefix size for that matter) */
2508 dur_offset = size_offset = 0;
2509 if (flags & TR_SAMPLE_DURATION) {
2510 GST_LOG_OBJECT (qtdemux, "entry duration present");
2511 dur_offset = entry_size;
2514 if (flags & TR_SAMPLE_SIZE) {
2515 GST_LOG_OBJECT (qtdemux, "entry size present");
2516 size_offset = entry_size;
2519 if (flags & TR_SAMPLE_FLAGS) {
2520 GST_LOG_OBJECT (qtdemux, "entry flags present");
2521 flags_offset = entry_size;
2524 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2525 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
2526 ct_offset = entry_size;
2530 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
2532 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
2534 if (stream->n_samples >=
2535 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
2538 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
2539 stream->n_samples, (guint) sizeof (QtDemuxSample),
2540 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
2542 /* create a new array of samples if it's the first sample parsed */
2543 if (stream->n_samples == 0)
2544 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
2545 /* or try to reallocate it with space enough to insert the new samples */
2547 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
2548 stream->n_samples + samples_count);
2549 if (stream->samples == NULL)
2552 if (qtdemux->fragment_start != -1) {
2553 timestamp = gst_util_uint64_scale_int (qtdemux->fragment_start,
2554 stream->timescale, GST_SECOND);
2555 qtdemux->fragment_start = -1;
2557 if (G_UNLIKELY (stream->n_samples == 0)) {
2558 /* the timestamp of the first sample is also provided by the tfra entry
2559 * but we shouldn't rely on it as it is at the end of files */
2562 /* subsequent fragments extend stream */
2564 stream->samples[stream->n_samples - 1].timestamp +
2565 stream->samples[stream->n_samples - 1].duration;
2568 sample = stream->samples + stream->n_samples;
2569 for (i = 0; i < samples_count; i++) {
2570 guint32 dur, size, sflags, ct;
2572 /* first read sample data */
2573 if (flags & TR_SAMPLE_DURATION) {
2574 dur = QT_UINT32 (data + dur_offset);
2576 dur = d_sample_duration;
2578 if (flags & TR_SAMPLE_SIZE) {
2579 size = QT_UINT32 (data + size_offset);
2581 size = d_sample_size;
2583 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2585 sflags = first_flags;
2587 sflags = d_sample_flags;
2589 } else if (flags & TR_SAMPLE_FLAGS) {
2590 sflags = QT_UINT32 (data + flags_offset);
2592 sflags = d_sample_flags;
2594 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2595 ct = QT_UINT32 (data + ct_offset);
2601 /* fill the sample information */
2602 sample->offset = *running_offset;
2603 sample->pts_offset = ct;
2604 sample->size = size;
2605 sample->timestamp = timestamp;
2606 sample->duration = dur;
2607 /* sample-is-difference-sample */
2608 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
2609 * now idea how it relates to bitfield other than massive LE/BE confusion */
2610 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
2611 *running_offset += size;
2616 stream->n_samples += samples_count;
2622 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
2627 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
2633 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
2634 "be larger than %uMB (broken file?)", stream->n_samples,
2635 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
2640 /* find stream with @id */
2641 static inline QtDemuxStream *
2642 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
2644 QtDemuxStream *stream;
2648 if (G_UNLIKELY (!id)) {
2649 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
2653 /* try to get it fast and simple */
2654 if (G_LIKELY (id <= qtdemux->n_streams)) {
2655 stream = qtdemux->streams[id - 1];
2656 if (G_LIKELY (stream->track_id == id))
2660 /* linear search otherwise */
2661 for (i = 0; i < qtdemux->n_streams; i++) {
2662 stream = qtdemux->streams[i];
2663 if (stream->track_id == id)
2666 if (qtdemux->mss_mode) {
2667 /* mss should have only 1 stream anyway */
2668 return qtdemux->streams[0];
2675 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
2676 QtDemuxStream ** stream, guint32 * default_sample_duration,
2677 guint32 * default_sample_size, guint32 * default_sample_flags,
2678 gint64 * base_offset)
2681 guint32 track_id = 0;
2683 if (!gst_byte_reader_skip (tfhd, 1) ||
2684 !gst_byte_reader_get_uint24_be (tfhd, &flags))
2687 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
2690 *stream = qtdemux_find_stream (qtdemux, track_id);
2691 if (G_UNLIKELY (!*stream))
2692 goto unknown_stream;
2694 if (flags & TF_BASE_DATA_OFFSET)
2695 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
2698 /* obtain stream defaults */
2699 qtdemux_parse_trex (qtdemux, *stream,
2700 default_sample_duration, default_sample_size, default_sample_flags);
2702 /* FIXME: Handle TF_SAMPLE_DESCRIPTION_INDEX properly */
2703 if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
2704 if (!gst_byte_reader_skip (tfhd, 4))
2707 if (flags & TF_DEFAULT_SAMPLE_DURATION)
2708 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
2711 if (flags & TF_DEFAULT_SAMPLE_SIZE)
2712 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
2715 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
2716 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
2723 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
2728 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
2734 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
2735 guint64 * decode_time)
2737 guint32 version = 0;
2739 if (!gst_byte_reader_get_uint32_be (br, &version))
2744 if (!gst_byte_reader_get_uint64_be (br, decode_time))
2747 guint32 dec_time = 0;
2748 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
2750 *decode_time = dec_time;
2753 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
2760 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
2766 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
2767 guint64 moof_offset, QtDemuxStream * stream)
2769 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node;
2770 GstByteReader trun_data, tfhd_data, tfdt_data;
2771 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
2772 gint64 base_offset, running_offset;
2774 /* NOTE @stream ignored */
2776 moof_node = g_node_new ((guint8 *) buffer);
2777 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
2778 qtdemux_node_dump (qtdemux, moof_node);
2780 /* unknown base_offset to start with */
2781 base_offset = running_offset = -1;
2782 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
2784 /* Fragment Header node */
2786 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
2790 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
2791 &ds_size, &ds_flags, &base_offset))
2794 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
2797 guint64 decode_time = 0;
2798 GstClockTime decode_time_ts;
2800 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
2802 /* FIXME, we can use decode_time to interpolate timestamps
2803 * in case the input timestamps are missing */
2804 decode_time_ts = gst_util_uint64_scale (decode_time, GST_SECOND,
2807 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GUINT64_FORMAT
2808 " (%" GST_TIME_FORMAT ")", decode_time,
2809 GST_TIME_ARGS (decode_time_ts));
2812 if (G_UNLIKELY (!stream)) {
2813 /* we lost track of offset, we'll need to regain it,
2814 * but can delay complaining until later or avoid doing so altogether */
2818 if (G_UNLIKELY (base_offset < -1))
2820 /* Track Run node */
2822 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
2825 qtdemux_parse_trun (qtdemux, &trun_data, stream,
2826 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
2828 /* iterate all siblings */
2829 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
2832 /* if no new base_offset provided for next traf,
2833 * base is end of current traf */
2834 base_offset = running_offset;
2835 running_offset = -1;
2837 /* iterate all siblings */
2838 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
2840 g_node_destroy (moof_node);
2845 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
2850 GST_DEBUG_OBJECT (qtdemux, "lost offset");
2855 g_node_destroy (moof_node);
2856 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
2857 (_("This file is corrupt and cannot be played.")), (NULL));
2862 /* might be used if some day we actually use mfra & co
2863 * for random access to fragments,
2864 * but that will require quite some modifications and much less relying
2865 * on a sample array */
2868 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node,
2869 QtDemuxStream * stream)
2871 guint64 time = 0, moof_offset = 0;
2872 guint32 ver_flags, track_id, len, num_entries, i;
2873 guint value_size, traf_size, trun_size, sample_size;
2874 GstBuffer *buf = NULL;
2878 gst_byte_reader_init (&tfra, (guint8 *) tfra_node->data + (4 + 4),
2879 QT_UINT32 ((guint8 *) tfra_node->data) - (4 + 4));
2881 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
2884 if (!(gst_byte_reader_get_uint32_be (&tfra, &track_id) &&
2885 gst_byte_reader_get_uint32_be (&tfra, &len) &&
2886 gst_byte_reader_get_uint32_be (&tfra, &num_entries)))
2889 GST_LOG_OBJECT (qtdemux, "id %d == stream id %d ?",
2890 track_id, stream->track_id);
2891 if (track_id != stream->track_id) {
2895 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
2896 sample_size = (len & 3) + 1;
2897 trun_size = ((len & 12) >> 2) + 1;
2898 traf_size = ((len & 48) >> 4) + 1;
2900 if (num_entries == 0)
2903 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
2904 value_size + value_size + traf_size + trun_size + sample_size))
2907 for (i = 0; i < num_entries; i++) {
2908 qt_atom_parser_get_offset (&tfra, value_size, &time);
2909 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
2910 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
2911 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
2912 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
2914 GST_LOG_OBJECT (qtdemux,
2915 "fragment time: %" GST_TIME_FORMAT " moof_offset: %u",
2916 GST_TIME_ARGS (gst_util_uint64_scale (time, GST_SECOND,
2917 stream->timescale)), moof_offset);
2919 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
2920 if (ret != GST_FLOW_OK)
2922 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
2923 moof_offset, stream);
2924 gst_buffer_unref (buf);
2932 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
2933 (_("This file is corrupt and cannot be played.")), (NULL));
2938 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
2944 qtdemux_parse_mfra (GstQTDemux * qtdemux, QtDemuxStream * stream)
2947 GNode *mfra_node, *tfra_node;
2950 if (!qtdemux->mfra_offset)
2953 ret = gst_qtdemux_pull_atom (qtdemux, qtdemux->mfra_offset, 0, &buffer);
2954 if (ret != GST_FLOW_OK)
2957 mfra_node = g_node_new ((guint8 *) GST_BUFFER_DATA (buffer));
2958 qtdemux_parse_node (qtdemux, mfra_node, GST_BUFFER_DATA (buffer),
2959 GST_BUFFER_SIZE (buffer));
2961 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
2964 qtdemux_parse_tfra (qtdemux, tfra_node, stream);
2965 /* iterate all siblings */
2966 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
2968 g_node_destroy (mfra_node);
2969 gst_buffer_unref (buffer);
2975 GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
2976 (_("This file is corrupt and cannot be played.")), (NULL));
2981 static GstFlowReturn
2982 qtdemux_parse_mfro (GstQTDemux * qtdemux, guint64 * mfra_offset,
2983 guint32 * mfro_size)
2985 GstFlowReturn ret = GST_FLOW_ERROR;
2986 GstBuffer *mfro = NULL;
2989 GstFormat fmt = GST_FORMAT_BYTES;
2991 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, &fmt, &len)) {
2992 GST_DEBUG_OBJECT (qtdemux, "upstream size not available; "
2993 "can not locate mfro");
2997 ret = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
2998 if (ret != GST_FLOW_OK)
3001 fourcc = QT_FOURCC (GST_BUFFER_DATA (mfro) + 4);
3002 if (fourcc != FOURCC_mfro)
3005 GST_INFO_OBJECT (qtdemux, "Found mfro atom: fragmented mp4 container");
3006 if (GST_BUFFER_SIZE (mfro) >= 16) {
3007 GST_DEBUG_OBJECT (qtdemux, "parsing 'mfro' atom");
3008 *mfro_size = QT_UINT32 (GST_BUFFER_DATA (mfro) + 12);
3009 if (*mfro_size >= len) {
3010 GST_WARNING_OBJECT (qtdemux, "mfro.size is invalid");
3011 ret = GST_FLOW_ERROR;
3014 *mfra_offset = len - *mfro_size;
3019 gst_buffer_unref (mfro);
3025 qtdemux_parse_fragmented (GstQTDemux * qtdemux)
3028 guint32 mfra_size = 0;
3029 guint64 mfra_offset = 0;
3032 qtdemux->fragmented = FALSE;
3034 /* We check here if it is a fragmented mp4 container */
3035 ret = qtdemux_parse_mfro (qtdemux, &mfra_offset, &mfra_size);
3036 if (ret == GST_FLOW_OK && mfra_size != 0 && mfra_offset != 0) {
3037 qtdemux->fragmented = TRUE;
3038 GST_DEBUG_OBJECT (qtdemux,
3039 "mfra atom expected at offset %" G_GUINT64_FORMAT, mfra_offset);
3040 qtdemux->mfra_offset = mfra_offset;
3045 static GstFlowReturn
3046 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
3050 GstBuffer *buf = NULL;
3051 GstFlowReturn ret = GST_FLOW_OK;
3052 guint64 cur_offset = qtdemux->offset;
3055 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
3056 if (G_UNLIKELY (ret != GST_FLOW_OK))
3058 gst_buffer_map (buf, &map, GST_MAP_READ);
3059 if (G_LIKELY (map.size >= 8))
3060 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
3061 gst_buffer_unmap (buf, &map);
3062 gst_buffer_unref (buf);
3064 /* maybe we already got most we needed, so only consider this eof */
3065 if (G_UNLIKELY (length == 0)) {
3066 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
3067 (_("Invalid atom size.")),
3068 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
3069 GST_FOURCC_ARGS (fourcc)));
3076 /* record for later parsing when needed */
3077 if (!qtdemux->moof_offset) {
3078 qtdemux->moof_offset = qtdemux->offset;
3087 GST_LOG_OBJECT (qtdemux,
3088 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
3089 GST_FOURCC_ARGS (fourcc), cur_offset);
3090 qtdemux->offset += length;
3095 GstBuffer *moov = NULL;
3097 if (qtdemux->got_moov) {
3098 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
3099 qtdemux->offset += length;
3103 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
3104 if (ret != GST_FLOW_OK)
3106 gst_buffer_map (moov, &map, GST_MAP_READ);
3108 if (length != map.size) {
3109 /* Some files have a 'moov' atom at the end of the file which contains
3110 * a terminal 'free' atom where the body of the atom is missing.
3111 * Check for, and permit, this special case.
3113 if (map.size >= 8) {
3114 guint8 *final_data = map.data + (map.size - 8);
3115 guint32 final_length = QT_UINT32 (final_data);
3116 guint32 final_fourcc = QT_FOURCC (final_data + 4);
3118 if (final_fourcc == FOURCC_free
3119 && map.size + final_length - 8 == length) {
3120 /* Ok, we've found that special case. Allocate a new buffer with
3121 * that free atom actually present. */
3122 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
3123 gst_buffer_fill (newmoov, 0, map.data, map.size);
3124 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
3125 gst_buffer_unmap (moov, &map);
3126 gst_buffer_unref (moov);
3128 gst_buffer_map (moov, &map, GST_MAP_READ);
3133 if (length != map.size) {
3134 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
3135 (_("This file is incomplete and cannot be played.")),
3136 ("We got less than expected (received %" G_GSIZE_FORMAT
3137 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
3138 (guint) length, cur_offset));
3139 gst_buffer_unmap (moov, &map);
3140 gst_buffer_unref (moov);
3141 ret = GST_FLOW_ERROR;
3144 qtdemux->offset += length;
3146 qtdemux_parse_moov (qtdemux, map.data, length);
3147 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
3149 qtdemux_parse_tree (qtdemux);
3150 g_node_destroy (qtdemux->moov_node);
3151 gst_buffer_unmap (moov, &map);
3152 gst_buffer_unref (moov);
3153 qtdemux->moov_node = NULL;
3154 qtdemux->got_moov = TRUE;
3160 GstBuffer *ftyp = NULL;
3162 /* extract major brand; might come in handy for ISO vs QT issues */
3163 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
3164 if (ret != GST_FLOW_OK)
3166 qtdemux->offset += length;
3167 gst_buffer_map (ftyp, &map, GST_MAP_READ);
3168 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
3169 gst_buffer_unmap (ftyp, &map);
3170 gst_buffer_unref (ftyp);
3175 GstBuffer *uuid = NULL;
3177 /* uuid are extension atoms */
3178 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
3179 if (ret != GST_FLOW_OK)
3181 qtdemux->offset += length;
3182 gst_buffer_map (uuid, &map, GST_MAP_READ);
3183 qtdemux_parse_uuid (qtdemux, map.data, map.size);
3184 gst_buffer_unmap (uuid, &map);
3185 gst_buffer_unref (uuid);
3190 GstBuffer *unknown = NULL;
3192 GST_LOG_OBJECT (qtdemux,
3193 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
3194 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
3196 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
3197 if (ret != GST_FLOW_OK)
3199 gst_buffer_map (unknown, &map, GST_MAP_READ);
3200 GST_MEMDUMP ("Unknown tag", map.data, map.size);
3201 gst_buffer_unmap (unknown, &map);
3202 gst_buffer_unref (unknown);
3203 qtdemux->offset += length;
3209 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
3210 /* digested all data, show what we have */
3211 qtdemux_prepare_streams (qtdemux);
3212 ret = qtdemux_expose_streams (qtdemux);
3214 qtdemux->state = QTDEMUX_STATE_MOVIE;
3215 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
3222 /* Seeks to the previous keyframe of the indexed stream and
3223 * aligns other streams with respect to the keyframe timestamp
3224 * of indexed stream. Only called in case of Reverse Playback
3226 static GstFlowReturn
3227 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
3230 guint32 seg_idx = 0, k_index = 0;
3231 guint32 ref_seg_idx, ref_k_index;
3232 guint64 k_pos = 0, last_stop = 0;
3233 QtDemuxSegment *seg = NULL;
3234 QtDemuxStream *ref_str = NULL;
3235 guint64 seg_media_start_mov; /* segment media start time in mov format */
3237 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
3238 * and finally align all the other streams on that timestamp with their
3239 * respective keyframes */
3240 for (n = 0; n < qtdemux->n_streams; n++) {
3241 QtDemuxStream *str = qtdemux->streams[n];
3243 seg_idx = gst_qtdemux_find_segment (qtdemux, str,
3244 qtdemux->segment.position);
3246 /* segment not found, continue with normal flow */
3250 /* No candidate yet, take that one */
3256 /* So that stream has a segment, we prefer video streams */
3257 if (str->subtype == FOURCC_vide) {
3263 if (G_UNLIKELY (!ref_str)) {
3264 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
3268 if (G_UNLIKELY (!ref_str->from_sample)) {
3269 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
3273 /* So that stream has been playing from from_sample to to_sample. We will
3274 * get the timestamp of the previous sample and search for a keyframe before
3275 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
3276 if (ref_str->subtype == FOURCC_vide) {
3277 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
3278 ref_str->from_sample - 1);
3280 if (ref_str->from_sample >= 10)
3281 k_index = ref_str->from_sample - 10;
3286 /* get current segment for that stream */
3287 seg = &ref_str->segments[ref_str->segment_index];
3288 /* convert seg->media_start to mov format time for timestamp comparison */
3289 seg_media_start_mov =
3290 gst_util_uint64_scale (seg->media_start, ref_str->timescale, GST_SECOND);
3291 /* Crawl back through segments to find the one containing this I frame */
3292 while (ref_str->samples[k_index].timestamp < seg_media_start_mov) {
3293 GST_DEBUG_OBJECT (qtdemux, "keyframe position is out of segment %u",
3294 ref_str->segment_index);
3295 if (G_UNLIKELY (!ref_str->segment_index)) {
3296 /* Reached first segment, let's consider it's EOS */
3299 ref_str->segment_index--;
3300 seg = &ref_str->segments[ref_str->segment_index];
3301 /* convert seg->media_start to mov format time for timestamp comparison */
3302 seg_media_start_mov =
3303 gst_util_uint64_scale (seg->media_start, ref_str->timescale,
3306 /* Calculate time position of the keyframe and where we should stop */
3308 (gst_util_uint64_scale (ref_str->samples[k_index].timestamp, GST_SECOND,
3309 ref_str->timescale) - seg->media_start) + seg->time;
3311 gst_util_uint64_scale (ref_str->samples[ref_str->from_sample].timestamp,
3312 GST_SECOND, ref_str->timescale);
3313 last_stop = (last_stop - seg->media_start) + seg->time;
3315 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
3316 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
3317 k_index, GST_TIME_ARGS (k_pos));
3319 /* Set last_stop with the keyframe timestamp we pushed of that stream */
3320 qtdemux->segment.position = last_stop;
3321 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
3322 GST_TIME_ARGS (last_stop));
3324 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
3325 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
3329 ref_seg_idx = ref_str->segment_index;
3330 ref_k_index = k_index;
3332 /* Align them all on this */
3333 for (n = 0; n < qtdemux->n_streams; n++) {
3335 guint64 media_start = 0, seg_time = 0;
3336 QtDemuxStream *str = qtdemux->streams[n];
3338 /* aligning reference stream again might lead to backing up to yet another
3339 * keyframe (due to timestamp rounding issues),
3340 * potentially putting more load on downstream; so let's try to avoid */
3341 if (str == ref_str) {
3342 seg_idx = ref_seg_idx;
3343 seg = &str->segments[seg_idx];
3344 k_index = ref_k_index;
3345 GST_DEBUG_OBJECT (qtdemux, "reference stream segment %d, "
3346 "sample at index %d", ref_str->segment_index, k_index);
3348 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
3349 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
3351 /* segment not found, continue with normal flow */
3355 /* get segment and time in the segment */
3356 seg = &str->segments[seg_idx];
3357 seg_time = k_pos - seg->time;
3359 /* get the media time in the segment */
3360 media_start = seg->media_start + seg_time;
3362 /* get the index of the sample with media time */
3363 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
3364 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u",
3365 GST_TIME_ARGS (media_start), index);
3367 /* find previous keyframe */
3368 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index);
3371 /* Remember until where we want to go */
3372 str->to_sample = str->from_sample - 1;
3373 /* Define our time position */
3374 str->time_position =
3375 (gst_util_uint64_scale (str->samples[k_index].timestamp, GST_SECOND,
3376 str->timescale) - seg->media_start) + seg->time;
3377 /* Now seek back in time */
3378 gst_qtdemux_move_stream (qtdemux, str, k_index);
3379 GST_DEBUG_OBJECT (qtdemux, "keyframe at %u, time position %"
3380 GST_TIME_FORMAT " playing from sample %u to %u", k_index,
3381 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
3387 return GST_FLOW_EOS;
3390 /* activate the given segment number @seg_idx of @stream at time @offset.
3391 * @offset is an absolute global position over all the segments.
3393 * This will push out a NEWSEGMENT event with the right values and
3394 * position the stream index to the first decodable sample before
3398 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
3399 guint32 seg_idx, guint64 offset)
3402 QtDemuxSegment *segment;
3403 guint32 index, kf_index;
3405 guint64 start, stop, time;
3408 GST_LOG_OBJECT (qtdemux, "activate segment %d, offset %" G_GUINT64_FORMAT,
3411 /* update the current segment */
3412 stream->segment_index = seg_idx;
3414 /* get the segment */
3415 segment = &stream->segments[seg_idx];
3417 if (G_UNLIKELY (offset < segment->time)) {
3418 GST_WARNING_OBJECT (qtdemux, "offset < segment->time %" G_GUINT64_FORMAT,
3423 /* segment lies beyond total indicated duration */
3424 if (G_UNLIKELY (qtdemux->segment.duration != -1 &&
3425 segment->time > qtdemux->segment.duration)) {
3426 GST_WARNING_OBJECT (qtdemux, "file duration %" G_GINT64_FORMAT
3427 " < segment->time %" G_GUINT64_FORMAT, qtdemux->segment.duration,
3432 /* get time in this segment */
3433 seg_time = offset - segment->time;
3435 GST_LOG_OBJECT (qtdemux, "seg_time %" GST_TIME_FORMAT,
3436 GST_TIME_ARGS (seg_time));
3438 if (G_UNLIKELY (seg_time > segment->duration)) {
3439 GST_LOG_OBJECT (qtdemux, "seg_time > segment->duration %" GST_TIME_FORMAT,
3440 GST_TIME_ARGS (segment->duration));
3444 /* qtdemux->segment.stop is in outside-time-realm, whereas
3445 * segment->media_stop is in track-time-realm.
3447 * In order to compare the two, we need to bring segment.stop
3448 * into the track-time-realm */
3450 stop = qtdemux->segment.stop;
3452 stop = qtdemux->segment.duration;
3454 stop = segment->media_stop;
3457 MIN (segment->media_stop, stop - segment->time + segment->media_start);
3459 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
3460 start = segment->time + seg_time;
3462 } else if (qtdemux->segment.rate >= 0) {
3463 start = MIN (segment->media_start + seg_time, stop);
3466 if (segment->media_start >= qtdemux->segment.start) {
3467 start = segment->media_start;
3468 time = segment->time;
3470 start = qtdemux->segment.start;
3471 time = segment->time + (qtdemux->segment.start - segment->media_start);
3474 start = MAX (segment->media_start, qtdemux->segment.start);
3475 stop = MIN (segment->media_start + seg_time, stop);
3478 GST_DEBUG_OBJECT (qtdemux, "newsegment %d from %" GST_TIME_FORMAT
3479 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
3480 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
3482 /* combine global rate with that of the segment */
3483 rate = segment->rate * qtdemux->segment.rate;
3485 /* update the segment values used for clipping */
3486 /* accumulate previous segments */
3487 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
3488 stream->segment.base += (stream->segment.stop - stream->segment.start) /
3489 ABS (stream->segment.rate);
3490 stream->segment.rate = rate;
3491 stream->segment.start = start;
3492 stream->segment.stop = stop;
3493 stream->segment.time = time;
3494 stream->segment.position = start;
3495 stream->segment.base =
3497 qtdemux->segment_base ? segment->time - qtdemux->segment_base : 0;
3499 /* now prepare and send the segment */
3501 event = gst_event_new_segment (&stream->segment);
3502 if (stream->segment_seqnum) {
3503 gst_event_set_seqnum (event, stream->segment_seqnum);
3504 stream->segment_seqnum = 0;
3506 gst_pad_push_event (stream->pad, event);
3507 /* clear to send tags on this pad now */
3508 gst_qtdemux_push_tags (qtdemux, stream);
3511 /* and move to the keyframe before the indicated media time of the
3513 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
3514 if (qtdemux->segment.rate >= 0) {
3515 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
3516 stream->to_sample = G_MAXUINT32;
3517 GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
3518 ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
3519 GST_TIME_ARGS (gst_util_uint64_scale (stream->
3520 samples[index].timestamp, GST_SECOND, stream->timescale)));
3522 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
3523 stream->to_sample = index;
3524 GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
3525 ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
3526 GST_TIME_ARGS (gst_util_uint64_scale (stream->
3527 samples[index].timestamp, GST_SECOND, stream->timescale)));
3530 GST_DEBUG_OBJECT (qtdemux, "No need to look for keyframe, "
3531 "this is an empty segment");
3535 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
3536 * encountered an error and printed a message so we return appropriately */
3540 /* we're at the right spot */
3541 if (index == stream->sample_index) {
3542 GST_DEBUG_OBJECT (qtdemux, "we are at the right index");
3546 /* find keyframe of the target index */
3547 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index);
3550 /* indent does stupid stuff with stream->samples[].timestamp */
3552 /* if we move forwards, we don't have to go back to the previous
3553 * keyframe since we already sent that. We can also just jump to
3554 * the keyframe right before the target index if there is one. */
3555 if (index > stream->sample_index) {
3556 /* moving forwards check if we move past a keyframe */
3557 if (kf_index > stream->sample_index) {
3558 GST_DEBUG_OBJECT (qtdemux,
3559 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT, kf_index,
3560 GST_TIME_ARGS (gst_util_uint64_scale (
3561 stream->samples[kf_index].timestamp,
3562 GST_SECOND, stream->timescale)));
3563 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
3565 GST_DEBUG_OBJECT (qtdemux,
3566 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT
3567 " already sent", kf_index,
3568 GST_TIME_ARGS (gst_util_uint64_scale (
3569 stream->samples[kf_index].timestamp,
3570 GST_SECOND, stream->timescale)));
3573 GST_DEBUG_OBJECT (qtdemux,
3574 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT, kf_index,
3575 GST_TIME_ARGS (gst_util_uint64_scale (
3576 stream->samples[kf_index].timestamp,
3577 GST_SECOND, stream->timescale)));
3578 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
3586 /* prepare to get the current sample of @stream, getting essential values.
3588 * This function will also prepare and send the segment when needed.
3590 * Return FALSE if the stream is EOS.
3593 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
3594 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
3595 guint64 * dts, guint64 * pts, guint64 * duration, gboolean * keyframe)
3597 QtDemuxSample *sample;
3598 guint64 time_position;
3601 g_return_val_if_fail (stream != NULL, FALSE);
3603 time_position = stream->time_position;
3604 if (G_UNLIKELY (time_position == -1))
3607 seg_idx = stream->segment_index;
3608 if (G_UNLIKELY (seg_idx == -1)) {
3609 /* find segment corresponding to time_position if we are looking
3611 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
3613 /* nothing found, we're really eos */
3618 /* different segment, activate it, sample_index will be set. */
3619 if (G_UNLIKELY (stream->segment_index != seg_idx))
3620 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
3622 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->
3623 segments[stream->segment_index]))) {
3624 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
3626 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
3627 " prepare empty sample");
3630 *pts = *dts = time_position;
3631 *duration = seg->duration - (time_position - seg->time);
3638 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
3639 stream->sample_index, stream->n_samples);
3641 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
3644 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
3645 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
3646 stream->sample_index);
3650 /* now get the info for the sample we're at */
3651 sample = &stream->samples[stream->sample_index];
3653 *dts = QTSAMPLE_DTS (stream, sample);
3654 *pts = QTSAMPLE_PTS (stream, sample);
3655 *offset = sample->offset;
3656 *size = sample->size;
3657 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
3658 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
3665 stream->time_position = -1;
3670 /* move to the next sample in @stream.
3672 * Moves to the next segment when needed.
3675 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
3677 QtDemuxSample *sample;
3678 QtDemuxSegment *segment;
3680 /* get current segment */
3681 segment = &stream->segments[stream->segment_index];
3683 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
3684 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
3688 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
3689 /* Mark the stream as EOS */
3690 GST_DEBUG_OBJECT (qtdemux,
3691 "reached max allowed sample %u, mark EOS", stream->to_sample);
3692 stream->time_position = -1;
3696 /* move to next sample */
3697 stream->sample_index++;
3698 stream->offset_in_sample = 0;
3700 /* reached the last sample, we need the next segment */
3701 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
3704 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
3705 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
3706 stream->sample_index);
3710 /* get next sample */
3711 sample = &stream->samples[stream->sample_index];
3713 /* see if we are past the segment */
3714 if (G_UNLIKELY (gst_util_uint64_scale (sample->timestamp,
3715 GST_SECOND, stream->timescale) >= segment->media_stop))
3718 if (gst_util_uint64_scale (sample->timestamp, GST_SECOND,
3719 stream->timescale) >= segment->media_start) {
3720 /* inside the segment, update time_position, looks very familiar to
3721 * GStreamer segments, doesn't it? */
3722 stream->time_position =
3723 (gst_util_uint64_scale (sample->timestamp, GST_SECOND,
3724 stream->timescale) - segment->media_start) + segment->time;
3726 /* not yet in segment, time does not yet increment. This means
3727 * that we are still prerolling keyframes to the decoder so it can
3728 * decode the first sample of the segment. */
3729 stream->time_position = segment->time;
3733 /* move to the next segment */
3736 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
3738 if (stream->segment_index == stream->n_segments - 1) {
3739 /* are we at the end of the last segment, we're EOS */
3740 stream->time_position = -1;
3742 /* else we're only at the end of the current segment */
3743 stream->time_position = segment->stop_time;
3745 /* make sure we select a new segment */
3746 stream->segment_index = -1;
3751 gst_qtdemux_sync_streams (GstQTDemux * demux)
3755 if (demux->n_streams <= 1)
3758 for (i = 0; i < demux->n_streams; i++) {
3759 QtDemuxStream *stream;
3760 GstClockTime end_time;
3762 stream = demux->streams[i];
3767 /* TODO advance time on subtitle streams here, if any some day */
3769 /* some clips/trailers may have unbalanced streams at the end,
3770 * so send EOS on shorter stream to prevent stalling others */
3772 /* do not mess with EOS if SEGMENT seeking */
3773 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
3776 if (demux->pullbased) {
3777 /* loop mode is sample time based */
3778 if (!STREAM_IS_EOS (stream))
3781 /* push mode is byte position based */
3782 if (stream->n_samples &&
3783 stream->samples[stream->n_samples - 1].offset >= demux->offset)
3787 if (stream->sent_eos)
3790 /* only act if some gap */
3791 end_time = stream->segments[stream->n_segments - 1].stop_time;
3792 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
3793 ", stream end: %" GST_TIME_FORMAT,
3794 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
3795 if (GST_CLOCK_TIME_IS_VALID (end_time)
3796 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
3797 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
3798 GST_PAD_NAME (stream->pad));
3799 stream->sent_eos = TRUE;
3800 gst_pad_push_event (stream->pad, gst_event_new_eos ());
3805 /* EOS and NOT_LINKED need to be combined. This means that we return:
3807 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
3808 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
3810 static GstFlowReturn
3811 gst_qtdemux_combine_flows (GstQTDemux * demux, GstFlowReturn ret)
3813 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
3815 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
3817 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
3821 /* the input buffer metadata must be writable. Returns NULL when the buffer is
3822 * completely clipped
3824 * Should be used only with raw buffers */
3826 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
3829 guint64 start, stop, cstart, cstop, diff;
3830 GstClockTime pts, duration;
3832 gint num_rate, denom_rate;
3837 osize = size = gst_buffer_get_size (buf);
3840 /* depending on the type, setup the clip parameters */
3841 if (stream->subtype == FOURCC_soun) {
3842 frame_size = stream->bytes_per_frame;
3843 num_rate = GST_SECOND;
3844 denom_rate = (gint) stream->rate;
3846 } else if (stream->subtype == FOURCC_vide) {
3848 num_rate = stream->fps_n;
3849 denom_rate = stream->fps_d;
3854 if (frame_size <= 0)
3855 goto bad_frame_size;
3857 /* we can only clip if we have a valid pts */
3858 pts = GST_BUFFER_PTS (buf);
3859 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
3862 duration = GST_BUFFER_DURATION (buf);
3864 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
3866 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
3870 stop = start + duration;
3872 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
3873 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
3876 /* see if some clipping happened */
3877 diff = cstart - start;
3883 /* bring clipped time to samples and to bytes */
3884 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
3887 GST_DEBUG_OBJECT (qtdemux,
3888 "clipping start to %" GST_TIME_FORMAT " %"
3889 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
3895 diff = stop - cstop;
3900 /* bring clipped time to samples and then to bytes */
3901 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
3903 GST_DEBUG_OBJECT (qtdemux,
3904 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
3905 " bytes", GST_TIME_ARGS (cstop), diff);
3910 if (offset != 0 || size != osize)
3911 gst_buffer_resize (buf, offset, size);
3913 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
3914 GST_BUFFER_PTS (buf) = pts;
3915 GST_BUFFER_DURATION (buf) = duration;
3919 /* dropped buffer */
3922 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
3927 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
3932 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
3937 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
3938 gst_buffer_unref (buf);
3943 /* the input buffer metadata must be writable,
3944 * but time/duration etc not yet set and need not be preserved */
3946 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
3953 /* not many cases for now */
3954 if (G_UNLIKELY (stream->fourcc == FOURCC_mp4s)) {
3955 /* send a one time dvd clut event */
3956 if (stream->pending_event && stream->pad)
3957 gst_pad_push_event (stream->pad, stream->pending_event);
3958 stream->pending_event = NULL;
3961 if (G_UNLIKELY (stream->subtype != FOURCC_text
3962 && stream->subtype != FOURCC_sbtl &&
3963 stream->subtype != FOURCC_subp)) {
3967 gst_buffer_map (buf, &map, GST_MAP_READ);
3969 /* empty buffer is sent to terminate previous subtitle */
3970 if (map.size <= 2) {
3971 gst_buffer_unmap (buf, &map);
3972 gst_buffer_unref (buf);
3975 if (stream->subtype == FOURCC_subp) {
3976 /* That's all the processing needed for subpictures */
3977 gst_buffer_unmap (buf, &map);
3981 nsize = GST_READ_UINT16_BE (map.data);
3982 nsize = MIN (nsize, map.size - 2);
3984 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
3987 /* takes care of UTF-8 validation or UTF-16 recognition,
3988 * no other encoding expected */
3989 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
3990 gst_buffer_unmap (buf, &map);
3992 gst_buffer_unref (buf);
3993 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
3995 /* this should not really happen unless the subtitle is corrupted */
3996 gst_buffer_unref (buf);
4000 /* FIXME ? convert optional subsequent style info to markup */
4005 /* Sets a buffer's attributes properly and pushes it downstream.
4006 * Also checks for additional actions and custom processing that may
4007 * need to be done first.
4009 static GstFlowReturn
4010 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
4011 QtDemuxStream * stream, GstBuffer * buf,
4012 guint64 dts, guint64 pts, guint64 duration, gboolean keyframe,
4013 guint64 position, guint64 byte_position)
4015 GstFlowReturn ret = GST_FLOW_OK;
4017 /* offset the timestamps according to the edit list */
4019 if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) {
4023 gst_buffer_map (buf, &map, GST_MAP_READ);
4024 url = g_strndup ((gchar *) map.data, map.size);
4025 gst_buffer_unmap (buf, &map);
4026 if (url != NULL && strlen (url) != 0) {
4027 /* we have RTSP redirect now */
4028 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
4029 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
4030 gst_structure_new ("redirect",
4031 "new-location", G_TYPE_STRING, url, NULL)));
4032 qtdemux->posted_redirect = TRUE;
4034 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
4040 /* position reporting */
4041 if (qtdemux->segment.rate >= 0) {
4042 qtdemux->segment.position = position;
4043 gst_qtdemux_sync_streams (qtdemux);
4046 if (G_UNLIKELY (!stream->pad)) {
4047 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
4048 gst_buffer_unref (buf);
4052 /* send out pending buffers */
4053 while (stream->buffers) {
4054 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
4056 if (G_UNLIKELY (stream->discont)) {
4057 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
4058 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
4059 stream->discont = FALSE;
4061 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
4064 gst_pad_push (stream->pad, buffer);
4066 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
4069 /* we're going to modify the metadata */
4070 buf = gst_buffer_make_writable (buf);
4072 if (G_UNLIKELY (stream->need_process))
4073 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
4079 GST_BUFFER_DTS (buf) = dts;
4080 GST_BUFFER_PTS (buf) = pts;
4081 GST_BUFFER_DURATION (buf) = duration;
4082 GST_BUFFER_OFFSET (buf) = -1;
4083 GST_BUFFER_OFFSET_END (buf) = -1;
4085 if (G_UNLIKELY (stream->rgb8_palette))
4086 gst_buffer_append_memory (buf, gst_memory_ref (stream->rgb8_palette));
4088 if (G_UNLIKELY (stream->padding)) {
4089 gst_buffer_resize (buf, stream->padding, -1);
4092 if (G_UNLIKELY (qtdemux->element_index)) {
4093 GstClockTime stream_time;
4096 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
4098 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
4099 GST_LOG_OBJECT (qtdemux,
4100 "adding association %" GST_TIME_FORMAT "-> %"
4101 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
4102 gst_index_add_association (qtdemux->element_index,
4104 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
4105 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
4106 GST_FORMAT_BYTES, byte_position, NULL);
4111 if (stream->need_clip)
4112 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
4114 if (G_UNLIKELY (buf == NULL))
4117 if (G_UNLIKELY (stream->discont)) {
4118 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
4119 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
4120 stream->discont = FALSE;
4122 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
4126 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
4127 stream->on_keyframe = FALSE;
4129 stream->on_keyframe = TRUE;
4133 GST_LOG_OBJECT (qtdemux,
4134 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
4135 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
4136 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
4137 GST_PAD_NAME (stream->pad));
4139 ret = gst_pad_push (stream->pad, buf);
4141 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
4142 /* mark position in stream, we'll need this to know when to send GAP event */
4143 stream->segment.position = pts + duration;
4150 static GstFlowReturn
4151 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
4153 GstFlowReturn ret = GST_FLOW_OK;
4154 GstBuffer *buf = NULL;
4155 QtDemuxStream *stream;
4158 guint64 dts = GST_CLOCK_TIME_NONE;
4159 guint64 pts = GST_CLOCK_TIME_NONE;
4160 guint64 duration = 0;
4161 gboolean keyframe = FALSE;
4162 guint sample_size = 0;
4168 gst_qtdemux_push_pending_newsegment (qtdemux);
4170 /* Figure out the next stream sample to output, min_time is expressed in
4171 * global time and runs over the edit list segments. */
4172 min_time = G_MAXUINT64;
4174 for (i = 0; i < qtdemux->n_streams; i++) {
4177 stream = qtdemux->streams[i];
4178 position = stream->time_position;
4180 /* position of -1 is EOS */
4181 if (position != -1 && position < min_time) {
4182 min_time = position;
4187 if (G_UNLIKELY (index == -1)) {
4188 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
4192 /* check for segment end */
4193 if (G_UNLIKELY (qtdemux->segment.stop != -1
4194 && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
4195 || (qtdemux->segment.rate < 0
4196 && qtdemux->segment.start > min_time))
4197 && qtdemux->streams[index]->on_keyframe)) {
4198 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
4199 qtdemux->streams[index]->time_position = -1;
4203 /* gap events for subtitle streams */
4204 for (i = 0; i < qtdemux->n_streams; i++) {
4205 stream = qtdemux->streams[i];
4206 if (stream->pad && (stream->subtype == FOURCC_subp
4207 || stream->subtype == FOURCC_text
4208 || stream->subtype == FOURCC_sbtl)) {
4209 /* send one second gap events until the stream catches up */
4210 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
4211 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
4212 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
4213 stream->segment.position + GST_SECOND < min_time) {
4215 gst_event_new_gap (stream->segment.position, GST_SECOND);
4216 gst_pad_push_event (stream->pad, gap);
4217 stream->segment.position += GST_SECOND;
4222 stream = qtdemux->streams[index];
4223 if (stream->new_caps) {
4224 gst_qtdemux_configure_stream (qtdemux, stream);
4225 qtdemux_do_allocation (qtdemux, stream);
4228 /* fetch info for the current sample of this stream */
4229 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
4230 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
4233 GST_DEBUG_OBJECT (qtdemux,
4234 "pushing from stream %d, empty %d offset %" G_GUINT64_FORMAT
4235 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
4236 ", duration %" GST_TIME_FORMAT, index, empty, offset, sample_size,
4237 GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
4239 if (G_UNLIKELY (empty)) {
4240 /* empty segment, push a gap and move to the next one */
4241 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
4242 stream->segment.position = pts + duration;
4246 /* hmm, empty sample, skip and move to next sample */
4247 if (G_UNLIKELY (sample_size <= 0))
4250 /* last pushed sample was out of boundary, goto next sample */
4251 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
4254 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
4257 GST_DEBUG_OBJECT (qtdemux,
4258 "size %d larger than stream max_buffer_size %d, trimming",
4259 sample_size, stream->max_buffer_size);
4261 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
4264 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
4267 if (stream->use_allocator) {
4268 /* if we have a per-stream allocator, use it */
4269 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
4272 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
4274 if (G_UNLIKELY (ret != GST_FLOW_OK))
4277 if (size != sample_size) {
4278 pts += gst_util_uint64_scale_int (GST_SECOND,
4279 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
4280 dts += gst_util_uint64_scale_int (GST_SECOND,
4281 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
4282 duration = gst_util_uint64_scale_int (GST_SECOND,
4283 size / stream->bytes_per_frame, stream->timescale);
4286 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
4287 dts, pts, duration, keyframe, min_time, offset);
4289 if (size != sample_size) {
4290 QtDemuxSample *sample = &stream->samples[stream->sample_index];
4291 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
4293 GstClockTime time_position = gst_util_uint64_scale (sample->timestamp +
4294 stream->offset_in_sample / stream->bytes_per_frame, GST_SECOND,
4296 if (time_position >= segment->media_start) {
4297 /* inside the segment, update time_position, looks very familiar to
4298 * GStreamer segments, doesn't it? */
4299 stream->time_position = (time_position - segment->media_start) +
4302 /* not yet in segment, time does not yet increment. This means
4303 * that we are still prerolling keyframes to the decoder so it can
4304 * decode the first sample of the segment. */
4305 stream->time_position = segment->time;
4310 ret = gst_qtdemux_combine_flows (qtdemux, ret);
4311 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
4312 * we have no more data for the pad to push */
4313 if (ret == GST_FLOW_EOS)
4316 stream->offset_in_sample += size;
4317 if (stream->offset_in_sample >= sample_size) {
4318 gst_qtdemux_advance_sample (qtdemux, stream);
4323 gst_qtdemux_advance_sample (qtdemux, stream);
4331 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
4337 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
4338 /* EOS will be raised if all are EOS */
4345 gst_qtdemux_loop (GstPad * pad)
4347 GstQTDemux *qtdemux;
4351 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
4353 cur_offset = qtdemux->offset;
4354 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %d",
4355 cur_offset, qtdemux->state);
4357 switch (qtdemux->state) {
4358 case QTDEMUX_STATE_INITIAL:
4359 case QTDEMUX_STATE_HEADER:
4360 ret = gst_qtdemux_loop_state_header (qtdemux);
4362 case QTDEMUX_STATE_MOVIE:
4363 ret = gst_qtdemux_loop_state_movie (qtdemux);
4364 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
4365 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
4373 /* if something went wrong, pause */
4374 if (ret != GST_FLOW_OK)
4378 gst_object_unref (qtdemux);
4384 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
4385 (NULL), ("streaming stopped, invalid state"));
4386 gst_pad_pause_task (pad);
4387 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
4392 const gchar *reason = gst_flow_get_name (ret);
4394 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
4396 gst_pad_pause_task (pad);
4398 /* fatal errors need special actions */
4400 if (ret == GST_FLOW_EOS) {
4401 if (qtdemux->n_streams == 0) {
4402 /* we have no streams, post an error */
4403 gst_qtdemux_post_no_playable_stream_error (qtdemux);
4405 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
4408 if ((stop = qtdemux->segment.stop) == -1)
4409 stop = qtdemux->segment.duration;
4411 if (qtdemux->segment.rate >= 0) {
4412 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
4413 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
4414 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
4415 GST_FORMAT_TIME, stop));
4416 gst_qtdemux_push_event (qtdemux,
4417 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
4419 /* For Reverse Playback */
4420 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
4421 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
4422 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
4423 GST_FORMAT_TIME, qtdemux->segment.start));
4424 gst_qtdemux_push_event (qtdemux,
4425 gst_event_new_segment_done (GST_FORMAT_TIME,
4426 qtdemux->segment.start));
4429 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
4430 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
4432 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
4433 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
4434 (NULL), ("streaming stopped, reason %s", reason));
4435 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
4444 * Returns if there are samples to be played.
4447 has_next_entry (GstQTDemux * demux)
4449 QtDemuxStream *stream;
4452 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
4454 for (i = 0; i < demux->n_streams; i++) {
4455 stream = demux->streams[i];
4457 if (stream->sample_index == -1) {
4458 stream->sample_index = 0;
4459 stream->offset_in_sample = 0;
4462 if (stream->sample_index >= stream->n_samples) {
4463 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
4466 GST_DEBUG_OBJECT (demux, "Found a sample");
4470 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
4477 * Returns the size of the first entry at the current offset.
4478 * If -1, there are none (which means EOS or empty file).
4481 next_entry_size (GstQTDemux * demux)
4483 QtDemuxStream *stream;
4486 guint64 smalloffs = (guint64) - 1;
4487 QtDemuxSample *sample;
4489 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
4492 for (i = 0; i < demux->n_streams; i++) {
4493 stream = demux->streams[i];
4495 if (stream->sample_index == -1) {
4496 stream->sample_index = 0;
4497 stream->offset_in_sample = 0;
4500 if (stream->sample_index >= stream->n_samples) {
4501 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
4505 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
4506 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
4507 stream->sample_index);
4511 sample = &stream->samples[stream->sample_index];
4513 GST_LOG_OBJECT (demux,
4514 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
4515 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
4516 sample->offset, sample->size);
4518 if (((smalloffs == -1)
4519 || (sample->offset < smalloffs)) && (sample->size)) {
4521 smalloffs = sample->offset;
4525 GST_LOG_OBJECT (demux,
4526 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
4527 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
4532 stream = demux->streams[smallidx];
4533 sample = &stream->samples[stream->sample_index];
4535 if (sample->offset >= demux->offset) {
4536 demux->todrop = sample->offset - demux->offset;
4537 return sample->size + demux->todrop;
4540 GST_DEBUG_OBJECT (demux,
4541 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
4546 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
4548 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
4550 gst_element_post_message (GST_ELEMENT_CAST (demux),
4551 gst_message_new_element (GST_OBJECT_CAST (demux),
4552 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
4556 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
4561 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
4564 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
4565 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
4566 GST_SEEK_TYPE_NONE, -1);
4568 res = gst_pad_push_event (demux->sinkpad, event);
4573 /* check for seekable upstream, above and beyond a mere query */
4575 gst_qtdemux_check_seekability (GstQTDemux * demux)
4578 gboolean seekable = FALSE;
4579 gint64 start = -1, stop = -1;
4581 if (demux->upstream_size)
4584 query = gst_query_new_seeking (GST_FORMAT_BYTES);
4585 if (!gst_pad_peer_query (demux->sinkpad, query)) {
4586 GST_DEBUG_OBJECT (demux, "seeking query failed");
4590 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
4592 /* try harder to query upstream size if we didn't get it the first time */
4593 if (seekable && stop == -1) {
4594 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
4595 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
4598 /* if upstream doesn't know the size, it's likely that it's not seekable in
4599 * practice even if it technically may be seekable */
4600 if (seekable && (start != 0 || stop <= start)) {
4601 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
4606 gst_query_unref (query);
4608 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
4609 G_GUINT64_FORMAT ")", seekable, start, stop);
4610 demux->upstream_seekable = seekable;
4611 demux->upstream_size = seekable ? stop : -1;
4614 /* FIXME, unverified after edit list updates */
4615 static GstFlowReturn
4616 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
4620 demux = GST_QTDEMUX (parent);
4621 gst_adapter_push (demux->adapter, inbuf);
4623 GST_DEBUG_OBJECT (demux,
4624 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
4625 demux->neededbytes, gst_adapter_available (demux->adapter));
4627 return gst_qtdemux_process_adapter (demux, FALSE);
4630 static GstFlowReturn
4631 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
4633 GstFlowReturn ret = GST_FLOW_OK;
4635 /* we never really mean to buffer that much */
4636 if (demux->neededbytes == -1) {
4640 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
4641 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
4643 GST_DEBUG_OBJECT (demux,
4644 "state:%d , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT,
4645 demux->state, demux->neededbytes, demux->offset);
4647 switch (demux->state) {
4648 case QTDEMUX_STATE_INITIAL:{
4653 gst_qtdemux_check_seekability (demux);
4655 data = gst_adapter_map (demux->adapter, demux->neededbytes);
4657 /* get fourcc/length, set neededbytes */
4658 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
4660 gst_adapter_unmap (demux->adapter);
4662 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
4663 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
4665 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4666 (_("This file is invalid and cannot be played.")),
4667 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
4668 GST_FOURCC_ARGS (fourcc)));
4669 ret = GST_FLOW_ERROR;
4672 if (fourcc == FOURCC_mdat) {
4673 gint next_entry = next_entry_size (demux);
4674 if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
4675 /* we have the headers, start playback */
4676 demux->state = QTDEMUX_STATE_MOVIE;
4677 demux->neededbytes = next_entry;
4678 demux->mdatleft = size;
4680 /* no headers yet, try to get them */
4683 guint64 old, target;
4686 old = demux->offset;
4687 target = old + size;
4689 /* try to jump over the atom with a seek */
4690 /* only bother if it seems worth doing so,
4691 * and avoids possible upstream/server problems */
4692 if (demux->upstream_seekable &&
4693 demux->upstream_size > 4 * (1 << 20)) {
4694 res = qtdemux_seek_offset (demux, target);
4696 GST_DEBUG_OBJECT (demux, "skipping seek");
4701 GST_DEBUG_OBJECT (demux, "seek success");
4702 /* remember the offset fo the first mdat so we can seek back to it
4703 * after we have the headers */
4704 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
4705 demux->first_mdat = old;
4706 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
4709 /* seek worked, continue reading */
4710 demux->offset = target;
4711 demux->neededbytes = 16;
4712 demux->state = QTDEMUX_STATE_INITIAL;
4714 /* seek failed, need to buffer */
4715 demux->offset = old;
4716 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
4717 /* there may be multiple mdat (or alike) buffers */
4719 if (demux->mdatbuffer)
4720 bs = gst_buffer_get_size (demux->mdatbuffer);
4723 if (size + bs > 10 * (1 << 20))
4725 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
4726 demux->neededbytes = size;
4727 if (!demux->mdatbuffer)
4728 demux->mdatoffset = demux->offset;
4731 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
4732 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4733 (_("This file is invalid and cannot be played.")),
4734 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
4735 GST_FOURCC_ARGS (fourcc), size));
4736 ret = GST_FLOW_ERROR;
4739 /* this means we already started buffering and still no moov header,
4740 * let's continue buffering everything till we get moov */
4741 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
4742 || fourcc == FOURCC_moof))
4744 demux->neededbytes = size;
4745 demux->state = QTDEMUX_STATE_HEADER;
4749 case QTDEMUX_STATE_HEADER:{
4753 GST_DEBUG_OBJECT (demux, "In header");
4755 data = gst_adapter_map (demux->adapter, demux->neededbytes);
4757 /* parse the header */
4758 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
4760 if (fourcc == FOURCC_moov) {
4761 /* in usual fragmented setup we could try to scan for more
4762 * and end up at the the moov (after mdat) again */
4763 if (demux->got_moov && demux->n_streams > 0 &&
4765 || demux->last_moov_offset == demux->offset)) {
4766 GST_DEBUG_OBJECT (demux,
4767 "Skipping moov atom as we have (this) one already");
4769 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
4771 if (demux->got_moov && demux->fragmented) {
4772 GST_DEBUG_OBJECT (demux,
4773 "Got a second moov, clean up data from old one");
4774 if (demux->moov_node)
4775 g_node_destroy (demux->moov_node);
4776 demux->moov_node = NULL;
4777 demux->moov_node_compressed = NULL;
4779 /* prepare newsegment to send when streaming actually starts */
4780 if (!demux->pending_newsegment)
4781 demux->pending_newsegment =
4782 gst_event_new_segment (&demux->segment);
4785 demux->last_moov_offset = demux->offset;
4787 qtdemux_parse_moov (demux, data, demux->neededbytes);
4788 qtdemux_node_dump (demux, demux->moov_node);
4789 qtdemux_parse_tree (demux);
4790 qtdemux_prepare_streams (demux);
4791 if (!demux->got_moov)
4792 qtdemux_expose_streams (demux);
4796 for (n = 0; n < demux->n_streams; n++) {
4797 QtDemuxStream *stream = demux->streams[n];
4799 gst_qtdemux_configure_stream (demux, stream);
4803 demux->got_moov = TRUE;
4805 g_node_destroy (demux->moov_node);
4806 demux->moov_node = NULL;
4807 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
4809 } else if (fourcc == FOURCC_moof) {
4810 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
4812 GstClockTime prev_pts;
4813 guint64 prev_offset;
4815 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
4818 * The timestamp of the moof buffer is relevant as some scenarios
4819 * won't have the initial timestamp in the atoms. Whenever a new
4820 * buffer has started, we get that buffer's PTS and use it as a base
4821 * timestamp for the trun entries.
4823 * To keep track of the current buffer timestamp and starting point
4824 * we use gst_adapter_prev_pts that gives us the PTS and the distance
4825 * from the beggining of the buffer, with the distance and demux->offset
4826 * we know if it is still the same buffer or not.
4828 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
4829 prev_offset = demux->offset - dist;
4830 if (demux->fragment_start_offset == -1
4831 || prev_offset > demux->fragment_start_offset) {
4832 demux->fragment_start_offset = prev_offset;
4833 demux->fragment_start = prev_pts;
4834 GST_DEBUG_OBJECT (demux,
4835 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
4836 GST_TIME_FORMAT, demux->fragment_start_offset,
4837 GST_TIME_ARGS (demux->fragment_start));
4840 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
4841 demux->offset, NULL)) {
4842 gst_adapter_unmap (demux->adapter);
4843 ret = GST_FLOW_ERROR;
4846 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
4847 if (demux->mss_mode && !demux->exposed) {
4848 if (!demux->pending_newsegment) {
4850 gst_segment_init (&segment, GST_FORMAT_TIME);
4851 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
4852 demux->pending_newsegment = gst_event_new_segment (&segment);
4854 qtdemux_expose_streams (demux);
4857 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
4859 } else if (fourcc == FOURCC_ftyp) {
4860 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
4861 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
4862 } else if (fourcc == FOURCC_uuid) {
4863 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
4864 qtdemux_parse_uuid (demux, data, demux->neededbytes);
4866 GST_WARNING_OBJECT (demux,
4867 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
4868 GST_FOURCC_ARGS (fourcc));
4869 /* Let's jump that one and go back to initial state */
4871 gst_adapter_unmap (demux->adapter);
4874 if (demux->mdatbuffer && demux->n_streams) {
4875 gsize remaining_data_size = 0;
4877 /* the mdat was before the header */
4878 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
4879 demux->n_streams, demux->mdatbuffer);
4880 /* restore our adapter/offset view of things with upstream;
4881 * put preceding buffered data ahead of current moov data.
4882 * This should also handle evil mdat, moov, mdat cases and alike */
4883 gst_adapter_flush (demux->adapter, demux->neededbytes);
4885 /* Store any remaining data after the mdat for later usage */
4886 remaining_data_size = gst_adapter_available (demux->adapter);
4887 if (remaining_data_size > 0) {
4888 g_assert (demux->restoredata_buffer == NULL);
4889 demux->restoredata_buffer =
4890 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
4891 demux->restoredata_offset = demux->offset + demux->neededbytes;
4892 GST_DEBUG_OBJECT (demux,
4893 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
4894 G_GUINT64_FORMAT, remaining_data_size,
4895 demux->restoredata_offset);
4898 gst_adapter_push (demux->adapter, demux->mdatbuffer);
4899 demux->mdatbuffer = NULL;
4900 demux->offset = demux->mdatoffset;
4901 demux->neededbytes = next_entry_size (demux);
4902 demux->state = QTDEMUX_STATE_MOVIE;
4903 demux->mdatleft = gst_adapter_available (demux->adapter);
4905 GST_DEBUG_OBJECT (demux, "Carrying on normally");
4906 gst_adapter_flush (demux->adapter, demux->neededbytes);
4908 /* only go back to the mdat if there are samples to play */
4909 if (demux->got_moov && demux->first_mdat != -1
4910 && has_next_entry (demux)) {
4913 /* we need to seek back */
4914 res = qtdemux_seek_offset (demux, demux->first_mdat);
4916 demux->offset = demux->first_mdat;
4918 GST_DEBUG_OBJECT (demux, "Seek back failed");
4921 demux->offset += demux->neededbytes;
4923 demux->neededbytes = 16;
4924 demux->state = QTDEMUX_STATE_INITIAL;
4929 case QTDEMUX_STATE_BUFFER_MDAT:{
4933 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
4935 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
4936 gst_buffer_extract (buf, 0, fourcc, 4);
4937 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
4938 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
4939 if (demux->mdatbuffer)
4940 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
4942 demux->mdatbuffer = buf;
4943 demux->offset += demux->neededbytes;
4944 demux->neededbytes = 16;
4945 demux->state = QTDEMUX_STATE_INITIAL;
4946 gst_qtdemux_post_progress (demux, 1, 1);
4950 case QTDEMUX_STATE_MOVIE:{
4952 QtDemuxStream *stream = NULL;
4953 QtDemuxSample *sample;
4955 guint64 dts, pts, duration;
4958 GST_DEBUG_OBJECT (demux,
4959 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
4961 if (demux->fragmented) {
4962 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
4964 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
4965 /* if needed data starts within this atom,
4966 * then it should not exceed this atom */
4967 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
4968 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4969 (_("This file is invalid and cannot be played.")),
4970 ("sample data crosses atom boundary"));
4971 ret = GST_FLOW_ERROR;
4974 demux->mdatleft -= demux->neededbytes;
4976 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
4977 /* so we are dropping more than left in this atom */
4978 demux->todrop -= demux->mdatleft;
4979 demux->neededbytes -= demux->mdatleft;
4980 demux->mdatleft = 0;
4981 /* need to resume atom parsing so we do not miss any other pieces */
4982 demux->state = QTDEMUX_STATE_INITIAL;
4983 demux->neededbytes = 16;
4985 /* check if there was any stored post mdat data from previous buffers */
4986 if (demux->restoredata_buffer) {
4987 g_assert (gst_adapter_available (demux->adapter) == 0);
4989 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
4990 demux->restoredata_buffer = NULL;
4991 demux->offset = demux->restoredata_offset;
4998 if (demux->todrop) {
4999 GST_LOG_OBJECT (demux, "Dropping %d bytes", demux->todrop);
5000 gst_adapter_flush (demux->adapter, demux->todrop);
5001 demux->neededbytes -= demux->todrop;
5002 demux->offset += demux->todrop;
5006 /* initial newsegment sent here after having added pads,
5007 * possible others in sink_event */
5008 if (G_UNLIKELY (demux->pending_newsegment)) {
5009 gst_qtdemux_push_pending_newsegment (demux);
5010 /* clear to send tags on all streams */
5011 for (i = 0; i < demux->n_streams; i++) {
5012 stream = demux->streams[i];
5013 gst_qtdemux_push_tags (demux, stream);
5014 if (stream->sparse) {
5015 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
5016 gst_pad_push_event (stream->pad,
5017 gst_event_new_gap (stream->segment.position,
5018 GST_CLOCK_TIME_NONE));
5023 /* Figure out which stream this packet belongs to */
5024 for (i = 0; i < demux->n_streams; i++) {
5025 stream = demux->streams[i];
5026 if (stream->sample_index >= stream->n_samples)
5028 GST_LOG_OBJECT (demux,
5029 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
5030 " / size:%d)", i, stream->sample_index,
5031 stream->samples[stream->sample_index].offset,
5032 stream->samples[stream->sample_index].size);
5034 if (stream->samples[stream->sample_index].offset == demux->offset)
5038 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
5039 goto unknown_stream;
5041 if (stream->new_caps) {
5042 gst_qtdemux_configure_stream (demux, stream);
5045 /* Put data in a buffer, set timestamps, caps, ... */
5046 sample = &stream->samples[stream->sample_index];
5048 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
5049 outbuf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
5050 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
5051 GST_FOURCC_ARGS (stream->fourcc));
5053 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
5055 dts = QTSAMPLE_DTS (stream, sample);
5056 pts = QTSAMPLE_PTS (stream, sample);
5057 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
5058 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5060 /* check for segment end */
5061 if (G_UNLIKELY (demux->segment.stop != -1
5062 && demux->segment.stop <= pts && stream->on_keyframe)) {
5063 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
5064 stream->time_position = -1; /* this means EOS */
5066 /* check if all streams are eos */
5068 for (i = 0; i < demux->n_streams; i++) {
5069 if (!STREAM_IS_EOS (demux->streams[i])) {
5075 if (ret == GST_FLOW_EOS) {
5076 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
5080 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
5081 dts, pts, duration, keyframe, dts, demux->offset);
5085 ret = gst_qtdemux_combine_flows (demux, ret);
5087 /* skip this data, stream is EOS */
5088 gst_adapter_flush (demux->adapter, demux->neededbytes);
5091 stream->sample_index++;
5092 stream->offset_in_sample = 0;
5094 /* update current offset and figure out size of next buffer */
5095 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
5096 demux->offset, demux->neededbytes);
5097 demux->offset += demux->neededbytes;
5098 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
5101 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
5102 if (demux->fragmented) {
5103 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
5104 /* there may be more to follow, only finish this atom */
5105 demux->todrop = demux->mdatleft;
5106 demux->neededbytes = demux->todrop;
5118 /* when buffering movie data, at least show user something is happening */
5119 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
5120 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
5121 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
5122 demux->neededbytes);
5131 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
5132 ret = GST_FLOW_ERROR;
5137 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
5143 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
5144 (NULL), ("qtdemuxer invalid state %d", demux->state));
5145 ret = GST_FLOW_ERROR;
5150 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
5151 (NULL), ("no 'moov' atom within the first 10 MB"));
5152 ret = GST_FLOW_ERROR;
5158 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
5163 query = gst_query_new_scheduling ();
5165 if (!gst_pad_peer_query (sinkpad, query)) {
5166 gst_query_unref (query);
5170 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
5171 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
5172 gst_query_unref (query);
5177 GST_DEBUG_OBJECT (sinkpad, "activating pull");
5178 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
5182 GST_DEBUG_OBJECT (sinkpad, "activating push");
5183 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
5188 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
5189 GstPadMode mode, gboolean active)
5192 GstQTDemux *demux = GST_QTDEMUX (parent);
5195 case GST_PAD_MODE_PUSH:
5196 demux->pullbased = FALSE;
5199 case GST_PAD_MODE_PULL:
5201 demux->pullbased = TRUE;
5202 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
5205 res = gst_pad_stop_task (sinkpad);
5217 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
5219 return g_malloc (items * size);
5223 qtdemux_zfree (void *opaque, void *addr)
5229 qtdemux_inflate (void *z_buffer, guint z_length, guint length)
5235 z = g_new0 (z_stream, 1);
5236 z->zalloc = qtdemux_zalloc;
5237 z->zfree = qtdemux_zfree;
5240 z->next_in = z_buffer;
5241 z->avail_in = z_length;
5243 buffer = (guint8 *) g_malloc (length);
5244 ret = inflateInit (z);
5245 while (z->avail_in > 0) {
5246 if (z->avail_out == 0) {
5248 buffer = (guint8 *) g_realloc (buffer, length);
5249 z->next_out = buffer + z->total_out;
5250 z->avail_out = 1024;
5252 ret = inflate (z, Z_SYNC_FLUSH);
5256 if (ret != Z_STREAM_END) {
5257 g_warning ("inflate() returned %d", ret);
5263 #endif /* HAVE_ZLIB */
5266 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
5270 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
5272 /* counts as header data */
5273 qtdemux->header_size += length;
5275 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
5276 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
5278 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
5284 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
5285 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
5286 if (dcom == NULL || cmvd == NULL)
5287 goto invalid_compression;
5289 method = QT_FOURCC ((guint8 *) dcom->data + 8);
5292 case GST_MAKE_FOURCC ('z', 'l', 'i', 'b'):{
5293 guint uncompressed_length;
5294 guint compressed_length;
5297 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
5298 compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12;
5299 GST_LOG ("length = %u", uncompressed_length);
5302 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
5303 compressed_length, uncompressed_length);
5305 qtdemux->moov_node_compressed = qtdemux->moov_node;
5306 qtdemux->moov_node = g_node_new (buf);
5308 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
5309 uncompressed_length);
5312 #endif /* HAVE_ZLIB */
5314 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
5315 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
5322 invalid_compression:
5324 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
5330 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
5333 while (G_UNLIKELY (buf < end)) {
5337 if (G_UNLIKELY (buf + 4 > end)) {
5338 GST_LOG_OBJECT (qtdemux, "buffer overrun");
5341 len = QT_UINT32 (buf);
5342 if (G_UNLIKELY (len == 0)) {
5343 GST_LOG_OBJECT (qtdemux, "empty container");
5346 if (G_UNLIKELY (len < 8)) {
5347 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
5350 if (G_UNLIKELY (len > (end - buf))) {
5351 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
5352 (gint) (end - buf));
5356 child = g_node_new ((guint8 *) buf);
5357 g_node_append (node, child);
5358 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
5359 qtdemux_parse_node (qtdemux, child, buf, len);
5367 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
5370 int len = QT_UINT32 (xdxt->data);
5371 guint8 *buf = xdxt->data;
5372 guint8 *end = buf + len;
5375 /* skip size and type */
5383 size = QT_UINT32 (buf);
5384 type = QT_FOURCC (buf + 4);
5386 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
5388 if (buf + size > end || size <= 0)
5394 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
5395 GST_FOURCC_ARGS (type));
5399 buffer = gst_buffer_new_and_alloc (size);
5400 gst_buffer_fill (buffer, 0, buf, size);
5401 stream->buffers = g_slist_append (stream->buffers, buffer);
5402 GST_LOG_OBJECT (qtdemux, "parsing theora header");
5405 buffer = gst_buffer_new_and_alloc (size);
5406 gst_buffer_fill (buffer, 0, buf, size);
5407 stream->buffers = g_slist_append (stream->buffers, buffer);
5408 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
5411 buffer = gst_buffer_new_and_alloc (size);
5412 gst_buffer_fill (buffer, 0, buf, size);
5413 stream->buffers = g_slist_append (stream->buffers, buffer);
5414 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
5417 GST_WARNING_OBJECT (qtdemux,
5418 "unknown theora cookie %" GST_FOURCC_FORMAT,
5419 GST_FOURCC_ARGS (type));
5428 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
5432 guint32 node_length = 0;
5433 const QtNodeType *type;
5436 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
5438 if (G_UNLIKELY (length < 8))
5439 goto not_enough_data;
5441 node_length = QT_UINT32 (buffer);
5442 fourcc = QT_FOURCC (buffer + 4);
5444 /* ignore empty nodes */
5445 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
5448 type = qtdemux_type_get (fourcc);
5450 end = buffer + length;
5452 GST_LOG_OBJECT (qtdemux,
5453 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
5454 GST_FOURCC_ARGS (fourcc), node_length, type->name);
5456 if (node_length > length)
5457 goto broken_atom_size;
5459 if (type->flags & QT_FLAG_CONTAINER) {
5460 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
5465 if (node_length < 20) {
5466 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
5469 GST_DEBUG_OBJECT (qtdemux,
5470 "parsing stsd (sample table, sample description) atom");
5471 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
5472 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
5482 /* also read alac (or whatever) in stead of mp4a in the following,
5483 * since a similar layout is used in other cases as well */
5484 if (fourcc == FOURCC_mp4a)
5489 /* There are two things we might encounter here: a true mp4a atom, and
5490 an mp4a entry in an stsd atom. The latter is what we're interested
5491 in, and it looks like an atom, but isn't really one. The true mp4a
5492 atom is short, so we detect it based on length here. */
5493 if (length < min_size) {
5494 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
5495 GST_FOURCC_ARGS (fourcc));
5499 /* 'version' here is the sound sample description version. Types 0 and
5500 1 are documented in the QTFF reference, but type 2 is not: it's
5501 described in Apple header files instead (struct SoundDescriptionV2
5503 version = QT_UINT16 (buffer + 16);
5505 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
5506 GST_FOURCC_ARGS (fourcc), version);
5508 /* parse any esds descriptors */
5520 GST_WARNING_OBJECT (qtdemux,
5521 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
5522 GST_FOURCC_ARGS (fourcc), version);
5527 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
5544 /* codec_data is contained inside these atoms, which all have
5545 * the same format. */
5547 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
5548 GST_FOURCC_ARGS (fourcc));
5549 version = QT_UINT32 (buffer + 16);
5550 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
5551 if (1 || version == 0x00000000) {
5552 buf = buffer + 0x32;
5554 /* FIXME Quicktime uses PASCAL string while
5555 * the iso format uses C strings. Check the file
5556 * type before attempting to parse the string here. */
5557 tlen = QT_UINT8 (buf);
5558 GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
5560 GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
5561 /* the string has a reserved space of 32 bytes so skip
5562 * the remaining 31 */
5564 buf += 4; /* and 4 bytes reserved */
5566 GST_MEMDUMP_OBJECT (qtdemux, "mp4v", buf, end - buf);
5568 qtdemux_parse_container (qtdemux, node, buf, end);
5574 GST_MEMDUMP_OBJECT (qtdemux, "H264", buffer, end - buffer);
5575 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
5580 GST_MEMDUMP_OBJECT (qtdemux, "avc1", buffer, end - buffer);
5581 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
5586 GST_MEMDUMP_OBJECT (qtdemux, "avc3", buffer, end - buffer);
5587 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
5592 GST_MEMDUMP_OBJECT (qtdemux, "H265", buffer, end - buffer);
5593 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
5598 GST_MEMDUMP_OBJECT (qtdemux, "hvc1", buffer, end - buffer);
5599 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
5604 GST_MEMDUMP_OBJECT (qtdemux, "hev1", buffer, end - buffer);
5605 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
5610 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
5615 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
5616 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
5621 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
5622 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
5623 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
5631 version = QT_UINT32 (buffer + 12);
5632 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
5639 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
5644 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
5649 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
5654 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
5658 if (!strcmp (type->name, "unknown"))
5659 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
5663 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
5664 GST_FOURCC_ARGS (fourcc));
5670 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5671 (_("This file is corrupt and cannot be played.")),
5672 ("Not enough data for an atom header, got only %u bytes", length));
5677 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5678 (_("This file is corrupt and cannot be played.")),
5679 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
5680 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
5687 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
5691 guint32 child_fourcc;
5693 for (child = g_node_first_child (node); child;
5694 child = g_node_next_sibling (child)) {
5695 buffer = (guint8 *) child->data;
5697 child_fourcc = QT_FOURCC (buffer + 4);
5699 if (G_UNLIKELY (child_fourcc == fourcc)) {
5707 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
5708 GstByteReader * parser)
5712 guint32 child_fourcc, child_len;
5714 for (child = g_node_first_child (node); child;
5715 child = g_node_next_sibling (child)) {
5716 buffer = (guint8 *) child->data;
5718 child_len = QT_UINT32 (buffer);
5719 child_fourcc = QT_FOURCC (buffer + 4);
5721 if (G_UNLIKELY (child_fourcc == fourcc)) {
5722 if (G_UNLIKELY (child_len < (4 + 4)))
5724 /* FIXME: must verify if atom length < parent atom length */
5725 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
5733 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
5734 GstByteReader * parser)
5738 guint32 child_fourcc, child_len;
5740 for (child = g_node_next_sibling (node); child;
5741 child = g_node_next_sibling (child)) {
5742 buffer = (guint8 *) child->data;
5744 child_fourcc = QT_FOURCC (buffer + 4);
5746 if (child_fourcc == fourcc) {
5748 child_len = QT_UINT32 (buffer);
5749 if (G_UNLIKELY (child_len < (4 + 4)))
5751 /* FIXME: must verify if atom length < parent atom length */
5752 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
5761 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
5763 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
5767 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
5769 /* FIXME: This can only reliably work if demuxers have a
5770 * separate streaming thread per srcpad. This should be
5771 * done in a demuxer base class, which integrates parts
5774 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
5779 query = gst_query_new_allocation (stream->caps, FALSE);
5781 if (!gst_pad_peer_query (stream->pad, query)) {
5782 /* not a problem, just debug a little */
5783 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
5786 if (stream->allocator)
5787 gst_object_unref (stream->allocator);
5789 if (gst_query_get_n_allocation_params (query) > 0) {
5790 /* try the allocator */
5791 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
5793 stream->use_allocator = TRUE;
5795 stream->allocator = NULL;
5796 gst_allocation_params_init (&stream->params);
5797 stream->use_allocator = FALSE;
5799 gst_query_unref (query);
5804 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
5806 if (stream->subtype == FOURCC_vide) {
5807 /* fps is calculated base on the duration of the first frames since
5808 * qt does not have a fixed framerate. */
5809 if ((stream->n_samples == 1) && (stream->min_duration == 0)) {
5814 /* we might need to scale the timescale to get precise framerate */
5815 const int required_scale = rint (log (10000) / 2.303); /* divide to get log10 */
5816 int current_scale = rint (log (stream->timescale) / 2.303);
5817 int factor = pow (10.0, MAX (0, required_scale - current_scale));
5819 stream->fps_n = stream->timescale * factor;
5821 if (stream->duration == 0 || stream->n_samples == 0)
5822 stream->fps_d = factor;
5825 gst_util_uint64_scale_int_round (stream->duration, factor,
5830 stream->caps = gst_caps_make_writable (stream->caps);
5832 gst_caps_set_simple (stream->caps,
5833 "width", G_TYPE_INT, stream->width,
5834 "height", G_TYPE_INT, stream->height,
5835 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
5837 /* calculate pixel-aspect-ratio using display width and height */
5838 GST_DEBUG_OBJECT (qtdemux,
5839 "video size %dx%d, target display size %dx%d", stream->width,
5840 stream->height, stream->display_width, stream->display_height);
5842 if (stream->display_width > 0 && stream->display_height > 0 &&
5843 stream->width > 0 && stream->height > 0) {
5846 /* calculate the pixel aspect ratio using the display and pixel w/h */
5847 n = stream->display_width * stream->height;
5848 d = stream->display_height * stream->width;
5851 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
5852 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
5853 GST_TYPE_FRACTION, n, d, NULL);
5856 /* qt file might have pasp atom */
5857 if (stream->par_w > 0 && stream->par_h > 0) {
5858 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
5859 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
5860 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
5863 } else if (stream->subtype == FOURCC_soun) {
5865 stream->caps = gst_caps_make_writable (stream->caps);
5866 if (stream->rate > 0)
5867 gst_caps_set_simple (stream->caps,
5868 "rate", G_TYPE_INT, (int) stream->rate, NULL);
5869 if (stream->n_channels > 0)
5870 gst_caps_set_simple (stream->caps,
5871 "channels", G_TYPE_INT, stream->n_channels, NULL);
5872 if (stream->n_channels > 2) {
5873 /* FIXME: Need to parse the 'chan' atom to get channel layouts
5874 * correctly; this is just the minimum we can do - assume
5875 * we don't actually have any channel positions. */
5876 gst_caps_set_simple (stream->caps,
5877 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
5883 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
5884 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
5885 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
5886 gst_pad_set_active (stream->pad, TRUE);
5888 gst_pad_use_fixed_caps (stream->pad);
5890 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
5891 if (stream->new_stream) {
5894 GstStreamFlags stream_flags;
5897 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
5900 if (gst_event_parse_group_id (event, &qtdemux->group_id))
5901 qtdemux->have_group_id = TRUE;
5903 qtdemux->have_group_id = FALSE;
5904 gst_event_unref (event);
5905 } else if (!qtdemux->have_group_id) {
5906 qtdemux->have_group_id = TRUE;
5907 qtdemux->group_id = gst_util_group_id_next ();
5910 stream->new_stream = FALSE;
5912 gst_pad_create_stream_id_printf (stream->pad,
5913 GST_ELEMENT_CAST (qtdemux), "%03u", stream->track_id);
5914 event = gst_event_new_stream_start (stream_id);
5915 if (qtdemux->have_group_id)
5916 gst_event_set_group_id (event, qtdemux->group_id);
5917 stream_flags = GST_STREAM_FLAG_NONE;
5918 if (stream->disabled)
5919 stream_flags |= GST_STREAM_FLAG_UNSELECT;
5921 stream_flags |= GST_STREAM_FLAG_SPARSE;
5922 gst_event_set_stream_flags (event, stream_flags);
5923 gst_pad_push_event (stream->pad, event);
5926 gst_pad_set_caps (stream->pad, stream->caps);
5927 stream->new_caps = FALSE;
5933 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
5934 QtDemuxStream * stream, GstTagList * list)
5936 /* consistent default for push based mode */
5937 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
5939 if (stream->subtype == FOURCC_vide) {
5940 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
5943 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
5946 gst_qtdemux_configure_stream (qtdemux, stream);
5947 qtdemux->n_video_streams++;
5948 } else if (stream->subtype == FOURCC_soun) {
5949 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
5952 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
5954 gst_qtdemux_configure_stream (qtdemux, stream);
5955 qtdemux->n_audio_streams++;
5956 } else if (stream->subtype == FOURCC_strm) {
5957 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
5958 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
5959 || stream->subtype == FOURCC_sbtl) {
5960 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
5963 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
5965 gst_qtdemux_configure_stream (qtdemux, stream);
5966 qtdemux->n_sub_streams++;
5967 } else if (stream->caps) {
5968 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
5971 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
5973 gst_qtdemux_configure_stream (qtdemux, stream);
5974 qtdemux->n_video_streams++;
5976 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5981 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
5982 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
5983 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
5984 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
5986 if (stream->pending_tags)
5987 gst_tag_list_unref (stream->pending_tags);
5988 stream->pending_tags = list;
5989 /* global tags go on each pad anyway */
5990 stream->send_global_tags = TRUE;
5996 /* find next atom with @fourcc starting at @offset */
5997 static GstFlowReturn
5998 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
5999 guint64 * length, guint32 fourcc)
6005 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
6006 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
6012 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
6013 if (G_UNLIKELY (ret != GST_FLOW_OK))
6015 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
6018 gst_buffer_unref (buf);
6021 gst_buffer_map (buf, &map, GST_MAP_READ);
6022 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
6023 gst_buffer_unmap (buf, &map);
6024 gst_buffer_unref (buf);
6026 if (G_UNLIKELY (*length == 0)) {
6027 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
6028 ret = GST_FLOW_ERROR;
6032 if (lfourcc == fourcc) {
6033 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
6037 GST_LOG_OBJECT (qtdemux,
6038 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
6039 GST_FOURCC_ARGS (fourcc), *offset);
6048 /* might simply have had last one */
6049 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
6054 /* should only do something in pull mode */
6055 /* call with OBJECT lock */
6056 static GstFlowReturn
6057 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
6059 guint64 length, offset;
6060 GstBuffer *buf = NULL;
6061 GstFlowReturn ret = GST_FLOW_OK;
6062 GstFlowReturn res = GST_FLOW_OK;
6065 offset = qtdemux->moof_offset;
6066 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
6069 GST_DEBUG_OBJECT (qtdemux, "no next moof");
6070 return GST_FLOW_EOS;
6073 /* best not do pull etc with lock held */
6074 GST_OBJECT_UNLOCK (qtdemux);
6076 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
6077 if (ret != GST_FLOW_OK)
6080 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
6081 if (G_UNLIKELY (ret != GST_FLOW_OK))
6083 gst_buffer_map (buf, &map, GST_MAP_READ);
6084 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
6085 gst_buffer_unmap (buf, &map);
6086 gst_buffer_unref (buf);
6091 gst_buffer_unmap (buf, &map);
6092 gst_buffer_unref (buf);
6096 /* look for next moof */
6097 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
6098 if (G_UNLIKELY (ret != GST_FLOW_OK))
6102 GST_OBJECT_LOCK (qtdemux);
6104 qtdemux->moof_offset = offset;
6110 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
6112 res = GST_FLOW_ERROR;
6117 /* maybe upstream temporarily flushing */
6118 if (ret != GST_FLOW_FLUSHING) {
6119 GST_DEBUG_OBJECT (qtdemux, "no next moof");
6122 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
6123 /* resume at current position next time */
6130 /* initialise bytereaders for stbl sub-atoms */
6132 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
6134 stream->stbl_index = -1; /* no samples have yet been parsed */
6135 stream->sample_index = -1;
6137 /* time-to-sample atom */
6138 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
6141 /* copy atom data into a new buffer for later use */
6142 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
6144 /* skip version + flags */
6145 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
6146 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
6148 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
6150 /* make sure there's enough data */
6151 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
6152 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
6153 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
6154 stream->n_sample_times);
6155 if (!stream->n_sample_times)
6159 /* sync sample atom */
6160 stream->stps_present = FALSE;
6161 if ((stream->stss_present =
6162 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
6163 &stream->stss) ? TRUE : FALSE) == TRUE) {
6164 /* copy atom data into a new buffer for later use */
6165 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
6167 /* skip version + flags */
6168 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
6169 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
6172 if (stream->n_sample_syncs) {
6173 /* make sure there's enough data */
6174 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
6178 /* partial sync sample atom */
6179 if ((stream->stps_present =
6180 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
6181 &stream->stps) ? TRUE : FALSE) == TRUE) {
6182 /* copy atom data into a new buffer for later use */
6183 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
6185 /* skip version + flags */
6186 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
6187 !gst_byte_reader_get_uint32_be (&stream->stps,
6188 &stream->n_sample_partial_syncs))
6191 /* if there are no entries, the stss table contains the real
6193 if (stream->n_sample_partial_syncs) {
6194 /* make sure there's enough data */
6195 if (!qt_atom_parser_has_chunks (&stream->stps,
6196 stream->n_sample_partial_syncs, 4))
6203 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
6206 /* copy atom data into a new buffer for later use */
6207 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
6209 /* skip version + flags */
6210 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
6211 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
6214 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
6217 if (!stream->n_samples)
6220 /* sample-to-chunk atom */
6221 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
6224 /* copy atom data into a new buffer for later use */
6225 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
6227 /* skip version + flags */
6228 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
6229 !gst_byte_reader_get_uint32_be (&stream->stsc,
6230 &stream->n_samples_per_chunk))
6233 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
6234 stream->n_samples_per_chunk);
6236 /* make sure there's enough data */
6237 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
6243 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
6244 stream->co_size = sizeof (guint32);
6245 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
6247 stream->co_size = sizeof (guint64);
6251 /* copy atom data into a new buffer for later use */
6252 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
6254 /* skip version + flags */
6255 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
6258 /* chunks_are_samples == TRUE means treat chunks as samples */
6259 stream->chunks_are_samples = stream->sample_size && !stream->sampled;
6260 if (stream->chunks_are_samples) {
6261 /* treat chunks as samples */
6262 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
6265 /* skip number of entries */
6266 if (!gst_byte_reader_skip (&stream->stco, 4))
6269 /* make sure there are enough data in the stsz atom */
6270 if (!stream->sample_size) {
6271 /* different sizes for each sample */
6272 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
6277 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
6278 stream->n_samples, (guint) sizeof (QtDemuxSample),
6279 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
6281 if (stream->n_samples >=
6282 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
6283 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
6284 "be larger than %uMB (broken file?)", stream->n_samples,
6285 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
6289 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
6290 if (!stream->samples) {
6291 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
6297 /* composition time-to-sample */
6298 if ((stream->ctts_present =
6299 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
6300 &stream->ctts) ? TRUE : FALSE) == TRUE) {
6301 /* copy atom data into a new buffer for later use */
6302 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
6304 /* skip version + flags */
6305 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
6306 || !gst_byte_reader_get_uint32_be (&stream->ctts,
6307 &stream->n_composition_times))
6310 /* make sure there's enough data */
6311 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
6320 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
6321 (_("This file is corrupt and cannot be played.")), (NULL));
6326 gst_qtdemux_stbl_free (stream);
6327 if (!qtdemux->fragmented) {
6328 /* not quite good */
6329 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
6332 /* may pick up samples elsewhere */
6338 /* collect samples from the next sample to be parsed up to sample @n for @stream
6339 * by reading the info from @stbl
6341 * This code can be executed from both the streaming thread and the seeking
6342 * thread so it takes the object lock to protect itself
6345 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
6348 QtDemuxSample *samples, *first, *cur, *last;
6349 guint32 n_samples_per_chunk;
6352 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
6353 GST_FOURCC_FORMAT ", pad %s", GST_FOURCC_ARGS (stream->fourcc),
6354 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
6356 n_samples = stream->n_samples;
6359 goto out_of_samples;
6361 GST_OBJECT_LOCK (qtdemux);
6362 if (n <= stream->stbl_index)
6363 goto already_parsed;
6365 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
6367 if (!stream->stsz.data) {
6368 /* so we already parsed and passed all the moov samples;
6369 * onto fragmented ones */
6370 g_assert (qtdemux->fragmented);
6374 /* pointer to the sample table */
6375 samples = stream->samples;
6377 /* starts from -1, moves to the next sample index to parse */
6378 stream->stbl_index++;
6380 /* keep track of the first and last sample to fill */
6381 first = &samples[stream->stbl_index];
6384 if (!stream->chunks_are_samples) {
6385 /* set the sample sizes */
6386 if (stream->sample_size == 0) {
6387 /* different sizes for each sample */
6388 for (cur = first; cur <= last; cur++) {
6389 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
6390 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
6391 (guint) (cur - samples), cur->size);
6394 /* samples have the same size */
6395 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
6396 for (cur = first; cur <= last; cur++)
6397 cur->size = stream->sample_size;
6401 n_samples_per_chunk = stream->n_samples_per_chunk;
6404 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
6407 if (stream->stsc_chunk_index >= stream->last_chunk
6408 || stream->stsc_chunk_index < stream->first_chunk) {
6409 stream->first_chunk =
6410 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
6411 stream->samples_per_chunk =
6412 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
6413 gst_byte_reader_skip_unchecked (&stream->stsc, 4);
6415 /* chunk numbers are counted from 1 it seems */
6416 if (G_UNLIKELY (stream->first_chunk == 0))
6419 --stream->first_chunk;
6421 /* the last chunk of each entry is calculated by taking the first chunk
6422 * of the next entry; except if there is no next, where we fake it with
6424 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
6425 stream->last_chunk = G_MAXUINT32;
6427 stream->last_chunk =
6428 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
6429 if (G_UNLIKELY (stream->last_chunk == 0))
6432 --stream->last_chunk;
6435 GST_LOG_OBJECT (qtdemux,
6436 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
6437 stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
6439 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
6442 if (stream->last_chunk != G_MAXUINT32) {
6443 if (!qt_atom_parser_peek_sub (&stream->stco,
6444 stream->first_chunk * stream->co_size,
6445 (stream->last_chunk - stream->first_chunk) * stream->co_size,
6450 stream->co_chunk = stream->stco;
6451 if (!gst_byte_reader_skip (&stream->co_chunk,
6452 stream->first_chunk * stream->co_size))
6456 stream->stsc_chunk_index = stream->first_chunk;
6459 last_chunk = stream->last_chunk;
6461 if (stream->chunks_are_samples) {
6462 cur = &samples[stream->stsc_chunk_index];
6464 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
6467 stream->stsc_chunk_index = j;
6472 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
6475 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
6476 "%" G_GUINT64_FORMAT, j, cur->offset);
6478 if (stream->samples_per_frame * stream->bytes_per_frame) {
6480 (stream->samples_per_chunk * stream->n_channels) /
6481 stream->samples_per_frame * stream->bytes_per_frame;
6483 cur->size = stream->samples_per_chunk;
6486 GST_DEBUG_OBJECT (qtdemux,
6487 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
6488 j, GST_TIME_ARGS (gst_util_uint64_scale (stream->stco_sample_index,
6489 GST_SECOND, stream->timescale)), cur->size);
6491 cur->timestamp = stream->stco_sample_index;
6492 cur->duration = stream->samples_per_chunk;
6493 cur->keyframe = TRUE;
6496 stream->stco_sample_index += stream->samples_per_chunk;
6498 stream->stsc_chunk_index = j;
6500 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
6501 guint32 samples_per_chunk;
6502 guint64 chunk_offset;
6504 if (!stream->stsc_sample_index
6505 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
6506 &stream->chunk_offset))
6509 samples_per_chunk = stream->samples_per_chunk;
6510 chunk_offset = stream->chunk_offset;
6512 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
6513 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
6514 G_GUINT64_FORMAT " and size %d",
6515 (guint) (cur - samples), stream->chunk_offset, cur->size);
6517 cur->offset = chunk_offset;
6518 chunk_offset += cur->size;
6521 if (G_UNLIKELY (cur > last)) {
6523 stream->stsc_sample_index = k + 1;
6524 stream->chunk_offset = chunk_offset;
6525 stream->stsc_chunk_index = j;
6529 stream->stsc_sample_index = 0;
6531 stream->stsc_chunk_index = j;
6533 stream->stsc_index++;
6536 if (stream->chunks_are_samples)
6540 guint32 n_sample_times;
6542 n_sample_times = stream->n_sample_times;
6545 for (i = stream->stts_index; i < n_sample_times; i++) {
6546 guint32 stts_samples;
6547 gint32 stts_duration;
6550 if (stream->stts_sample_index >= stream->stts_samples
6551 || !stream->stts_sample_index) {
6553 stream->stts_samples =
6554 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
6555 stream->stts_duration =
6556 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
6558 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
6559 i, stream->stts_samples, stream->stts_duration);
6561 stream->stts_sample_index = 0;
6564 stts_samples = stream->stts_samples;
6565 stts_duration = stream->stts_duration;
6566 stts_time = stream->stts_time;
6568 for (j = stream->stts_sample_index; j < stts_samples; j++) {
6569 GST_DEBUG_OBJECT (qtdemux,
6570 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
6571 (guint) (cur - samples), j,
6572 GST_TIME_ARGS (gst_util_uint64_scale (stts_time, GST_SECOND,
6573 stream->timescale)));
6575 cur->timestamp = stts_time;
6576 cur->duration = stts_duration;
6578 /* avoid 32-bit wrap-around,
6579 * but still mind possible 'negative' duration */
6580 stts_time += (gint64) stts_duration;
6583 if (G_UNLIKELY (cur > last)) {
6585 stream->stts_time = stts_time;
6586 stream->stts_sample_index = j + 1;
6590 stream->stts_sample_index = 0;
6591 stream->stts_time = stts_time;
6592 stream->stts_index++;
6594 /* fill up empty timestamps with the last timestamp, this can happen when
6595 * the last samples do not decode and so we don't have timestamps for them.
6596 * We however look at the last timestamp to estimate the track length so we
6597 * need something in here. */
6598 for (; cur < last; cur++) {
6599 GST_DEBUG_OBJECT (qtdemux,
6600 "fill sample %d: timestamp %" GST_TIME_FORMAT,
6601 (guint) (cur - samples),
6602 GST_TIME_ARGS (gst_util_uint64_scale (stream->stts_time, GST_SECOND,
6603 stream->timescale)));
6604 cur->timestamp = stream->stts_time;
6610 /* sample sync, can be NULL */
6611 if (stream->stss_present == TRUE) {
6612 guint32 n_sample_syncs;
6614 n_sample_syncs = stream->n_sample_syncs;
6616 if (!n_sample_syncs) {
6617 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
6618 stream->all_keyframe = TRUE;
6620 for (i = stream->stss_index; i < n_sample_syncs; i++) {
6621 /* note that the first sample is index 1, not 0 */
6624 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
6626 if (G_LIKELY (index > 0 && index <= n_samples)) {
6628 samples[index].keyframe = TRUE;
6629 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
6630 /* and exit if we have enough samples */
6631 if (G_UNLIKELY (index >= n)) {
6638 stream->stss_index = i;
6641 /* stps marks partial sync frames like open GOP I-Frames */
6642 if (stream->stps_present == TRUE) {
6643 guint32 n_sample_partial_syncs;
6645 n_sample_partial_syncs = stream->n_sample_partial_syncs;
6647 /* if there are no entries, the stss table contains the real
6649 if (n_sample_partial_syncs) {
6650 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
6651 /* note that the first sample is index 1, not 0 */
6654 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
6656 if (G_LIKELY (index > 0 && index <= n_samples)) {
6658 samples[index].keyframe = TRUE;
6659 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
6660 /* and exit if we have enough samples */
6661 if (G_UNLIKELY (index >= n)) {
6668 stream->stps_index = i;
6672 /* no stss, all samples are keyframes */
6673 stream->all_keyframe = TRUE;
6674 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
6679 /* composition time to sample */
6680 if (stream->ctts_present == TRUE) {
6681 guint32 n_composition_times;
6683 gint32 ctts_soffset;
6685 /* Fill in the pts_offsets */
6687 n_composition_times = stream->n_composition_times;
6689 for (i = stream->ctts_index; i < n_composition_times; i++) {
6690 if (stream->ctts_sample_index >= stream->ctts_count
6691 || !stream->ctts_sample_index) {
6692 stream->ctts_count =
6693 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
6694 stream->ctts_soffset =
6695 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
6696 stream->ctts_sample_index = 0;
6699 ctts_count = stream->ctts_count;
6700 ctts_soffset = stream->ctts_soffset;
6702 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
6703 cur->pts_offset = ctts_soffset;
6706 if (G_UNLIKELY (cur > last)) {
6708 stream->ctts_sample_index = j + 1;
6712 stream->ctts_sample_index = 0;
6713 stream->ctts_index++;
6717 stream->stbl_index = n;
6718 /* if index has been completely parsed, free data that is no-longer needed */
6719 if (n + 1 == stream->n_samples) {
6720 gst_qtdemux_stbl_free (stream);
6721 GST_DEBUG_OBJECT (qtdemux,
6722 "parsed all available samples; checking for more");
6723 while (n + 1 == stream->n_samples)
6724 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
6727 GST_OBJECT_UNLOCK (qtdemux);
6734 GST_LOG_OBJECT (qtdemux,
6735 "Tried to parse up to sample %u but this sample has already been parsed",
6737 /* if fragmented, there may be more */
6738 if (qtdemux->fragmented && n == stream->stbl_index)
6740 GST_OBJECT_UNLOCK (qtdemux);
6746 GST_LOG_OBJECT (qtdemux,
6747 "Tried to parse up to sample %u but there are only %u samples", n + 1,
6749 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
6750 (_("This file is corrupt and cannot be played.")), (NULL));
6755 GST_OBJECT_UNLOCK (qtdemux);
6756 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
6757 (_("This file is corrupt and cannot be played.")), (NULL));
6762 /* collect all segment info for @stream.
6765 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
6770 /* parse and prepare segment info from the edit list */
6771 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
6772 stream->n_segments = 0;
6773 stream->segments = NULL;
6774 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
6778 guint64 time, stime;
6781 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
6782 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
6785 buffer = elst->data;
6787 n_segments = QT_UINT32 (buffer + 12);
6789 /* we might allocate a bit too much, at least allocate 1 segment */
6790 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
6792 /* segments always start from 0 */
6796 for (i = 0; i < n_segments; i++) {
6799 QtDemuxSegment *segment;
6802 media_time = QT_UINT32 (buffer + 20 + i * 12);
6803 duration = QT_UINT32 (buffer + 16 + i * 12);
6805 segment = &stream->segments[count++];
6807 /* time and duration expressed in global timescale */
6808 segment->time = stime;
6809 /* add non scaled values so we don't cause roundoff errors */
6811 stime = gst_util_uint64_scale (time, GST_SECOND, qtdemux->timescale);
6812 segment->stop_time = stime;
6813 segment->duration = stime - segment->time;
6814 /* media_time expressed in stream timescale */
6815 if (media_time != G_MAXUINT32) {
6816 segment->media_start =
6817 gst_util_uint64_scale (media_time, GST_SECOND, stream->timescale);
6818 segment->media_stop = segment->media_start + segment->duration;
6820 segment->media_start = GST_CLOCK_TIME_NONE;
6821 segment->media_stop = GST_CLOCK_TIME_NONE;
6823 rate_int = GST_READ_UINT32_BE (buffer + 24 + i * 12);
6825 if (rate_int <= 1) {
6826 /* 0 is not allowed, some programs write 1 instead of the floating point
6828 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
6832 segment->rate = rate_int / 65536.0;
6835 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
6836 ", duration %" GST_TIME_FORMAT ", media_time %" GST_TIME_FORMAT
6837 ", rate %g, (%d)", i, GST_TIME_ARGS (segment->time),
6838 GST_TIME_ARGS (segment->duration),
6839 GST_TIME_ARGS (segment->media_start), segment->rate, rate_int);
6841 GST_DEBUG_OBJECT (qtdemux, "found %d segments", count);
6842 stream->n_segments = count;
6846 /* push based does not handle segments, so act accordingly here,
6847 * and warn if applicable */
6848 if (!qtdemux->pullbased) {
6849 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
6850 /* remove and use default one below, we stream like it anyway */
6851 g_free (stream->segments);
6852 stream->segments = NULL;
6853 stream->n_segments = 0;
6856 /* no segments, create one to play the complete trak */
6857 if (stream->n_segments == 0) {
6858 GstClockTime stream_duration =
6859 gst_util_uint64_scale (stream->duration, GST_SECOND, stream->timescale);
6861 if (stream->segments == NULL)
6862 stream->segments = g_new (QtDemuxSegment, 1);
6864 /* represent unknown our way */
6865 if (stream_duration == 0)
6866 stream_duration = -1;
6868 stream->segments[0].time = 0;
6869 stream->segments[0].stop_time = stream_duration;
6870 stream->segments[0].duration = stream_duration;
6871 stream->segments[0].media_start = 0;
6872 stream->segments[0].media_stop = stream_duration;
6873 stream->segments[0].rate = 1.0;
6875 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
6876 GST_TIME_ARGS (stream_duration));
6877 stream->n_segments = 1;
6879 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
6885 * Parses the stsd atom of a svq3 trak looking for
6886 * the SMI and gama atoms.
6889 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
6890 guint8 ** gamma, GstBuffer ** seqh)
6892 guint8 *_gamma = NULL;
6893 GstBuffer *_seqh = NULL;
6894 guint8 *stsd_data = stsd->data;
6895 guint32 length = QT_UINT32 (stsd_data);
6899 GST_WARNING_OBJECT (qtdemux, "stsd too short");
6905 version = QT_UINT16 (stsd_data);
6910 while (length > 8) {
6911 guint32 fourcc, size;
6913 size = QT_UINT32 (stsd_data);
6914 fourcc = QT_FOURCC (stsd_data + 4);
6915 data = stsd_data + 8;
6918 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
6919 "svq3 atom parsing");
6928 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
6929 " for gama atom, expected 12", size);
6934 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
6936 if (_seqh != NULL) {
6937 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
6938 " found, ignoring");
6940 seqh_size = QT_UINT32 (data + 4);
6941 if (seqh_size > 0) {
6942 _seqh = gst_buffer_new_and_alloc (seqh_size);
6943 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
6950 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
6951 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
6955 if (size <= length) {
6961 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
6964 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
6965 G_GUINT16_FORMAT, version);
6976 gst_buffer_unref (_seqh);
6981 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
6988 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
6989 * atom that might contain a 'data' atom with the rtsp uri.
6990 * This case was reported in bug #597497, some info about
6991 * the hndl atom can be found in TN1195
6993 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
6994 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
6997 guint32 dref_num_entries = 0;
6998 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
6999 gst_byte_reader_skip (&dref, 4) &&
7000 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
7003 /* search dref entries for hndl atom */
7004 for (i = 0; i < dref_num_entries; i++) {
7005 guint32 size = 0, type;
7006 guint8 string_len = 0;
7007 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
7008 qt_atom_parser_get_fourcc (&dref, &type)) {
7009 if (type == FOURCC_hndl) {
7010 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
7012 /* skip data reference handle bytes and the
7013 * following pascal string and some extra 4
7014 * bytes I have no idea what are */
7015 if (!gst_byte_reader_skip (&dref, 4) ||
7016 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
7017 !gst_byte_reader_skip (&dref, string_len + 4)) {
7018 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
7022 /* iterate over the atoms to find the data atom */
7023 while (gst_byte_reader_get_remaining (&dref) >= 8) {
7027 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
7028 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
7029 if (atom_type == FOURCC_data) {
7030 const guint8 *uri_aux = NULL;
7032 /* found the data atom that might contain the rtsp uri */
7033 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
7034 "hndl atom, interpreting it as an URI");
7035 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
7037 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
7038 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
7040 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
7041 "didn't contain a rtsp address");
7043 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
7048 /* skipping to the next entry */
7049 if (!gst_byte_reader_skip (&dref, atom_size - 8))
7052 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
7059 /* skip to the next entry */
7060 if (!gst_byte_reader_skip (&dref, size - 8))
7063 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
7066 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
7073 less_than (gconstpointer a, gconstpointer b)
7075 const guint32 *av = a, *bv = b;
7080 #define AMR_NB_ALL_MODES 0x81ff
7081 #define AMR_WB_ALL_MODES 0x83ff
7083 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
7085 /* The 'damr' atom is of the form:
7087 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
7088 * 32 b 8 b 16 b 8 b 8 b
7090 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
7091 * represents the highest mode used in the stream (and thus the maximum
7092 * bitrate), with a couple of special cases as seen below.
7095 /* Map of frame type ID -> bitrate */
7096 static const guint nb_bitrates[] = {
7097 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
7099 static const guint wb_bitrates[] = {
7100 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
7106 gst_buffer_map (buf, &map, GST_MAP_READ);
7108 if (map.size != 0x11) {
7109 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
7113 if (QT_FOURCC (map.data + 4) != GST_MAKE_FOURCC ('d', 'a', 'm', 'r')) {
7114 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
7115 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
7119 mode_set = QT_UINT16 (map.data + 13);
7121 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
7122 max_mode = 7 + (wb ? 1 : 0);
7124 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
7125 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
7127 if (max_mode == -1) {
7128 GST_DEBUG ("No mode indication was found (mode set) = %x",
7133 gst_buffer_unmap (buf, &map);
7134 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
7137 gst_buffer_unmap (buf, &map);
7142 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
7143 GstByteReader * reader, guint32 * matrix, const gchar * atom)
7146 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
7152 if (gst_byte_reader_get_remaining (reader) < 36)
7155 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
7156 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
7157 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
7158 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
7159 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
7160 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
7161 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
7162 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
7163 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
7165 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
7166 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
7167 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
7169 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
7170 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
7172 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
7173 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
7180 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
7181 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
7188 * This macro will only compare value abdegh, it expects cfi to have already
7191 #define QTCHECK_MATRIX(m,a,b,d,e,g,h) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
7192 (m)[3] == (d << 16) && (m)[4] == (e << 16) && \
7193 (m)[6] == (g << 16) && (m)[7] == (h << 16))
7195 /* only handle the cases where the last column has standard values */
7196 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
7197 const gchar *rotation_tag = NULL;
7199 /* no rotation needed */
7200 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1, 0, 0)) {
7202 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0,
7203 stream->display_height, 0)) {
7204 rotation_tag = "rotate-90";
7205 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16,
7206 stream->display_width, stream->display_height)) {
7207 rotation_tag = "rotate-180";
7208 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0, 0,
7209 stream->display_width)) {
7210 rotation_tag = "rotate-270";
7212 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
7215 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
7217 if (rotation_tag != NULL) {
7218 if (*taglist == NULL)
7219 *taglist = gst_tag_list_new_empty ();
7220 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
7221 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
7224 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
7229 * With each track we associate a new QtDemuxStream that contains all the info
7231 * traks that do not decode to something (like strm traks) will not have a pad.
7234 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
7251 QtDemuxStream *stream = NULL;
7252 gboolean new_stream = FALSE;
7253 GstTagList *list = NULL;
7254 gchar *codec = NULL;
7255 const guint8 *stsd_data;
7256 guint16 lang_code; /* quicktime lang code or packed iso code */
7258 guint32 tkhd_flags = 0;
7259 guint8 tkhd_version = 0;
7261 guint value_size, stsd_len, len;
7264 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
7266 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
7267 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
7268 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
7271 /* pick between 64 or 32 bits */
7272 value_size = tkhd_version == 1 ? 8 : 4;
7273 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
7274 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
7277 if (!qtdemux->got_moov) {
7278 if (qtdemux_find_stream (qtdemux, track_id))
7279 goto existing_stream;
7280 stream = _create_stream ();
7281 stream->track_id = track_id;
7284 stream = qtdemux_find_stream (qtdemux, track_id);
7286 GST_WARNING_OBJECT (qtdemux, "Stream not found, going to ignore it");
7291 if ((tkhd_flags & 1) == 0)
7292 stream->disabled = TRUE;
7294 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
7295 tkhd_version, tkhd_flags, stream->track_id);
7297 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
7300 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
7301 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
7302 if (qtdemux->major_brand != FOURCC_mjp2 ||
7303 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
7307 len = QT_UINT32 ((guint8 *) mdhd->data);
7308 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
7309 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
7310 if (version == 0x01000000) {
7313 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
7314 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
7315 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
7319 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
7320 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
7321 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
7324 if (lang_code < 0x800) {
7325 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
7327 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
7328 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
7329 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
7330 stream->lang_id[3] = 0;
7333 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
7335 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
7337 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
7338 lang_code, stream->lang_id);
7340 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
7343 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
7344 /* chapters track reference */
7345 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
7347 gsize length = GST_READ_UINT32_BE (chap->data);
7348 if (qtdemux->chapters_track_id)
7349 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
7352 qtdemux->chapters_track_id =
7353 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
7358 /* fragmented files may have bogus duration in moov */
7359 if (!qtdemux->fragmented &&
7360 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
7361 guint64 tdur1, tdur2;
7363 /* don't overflow */
7364 tdur1 = stream->timescale * (guint64) qtdemux->duration;
7365 tdur2 = qtdemux->timescale * (guint64) stream->duration;
7368 * some of those trailers, nowadays, have prologue images that are
7369 * themselves vide tracks as well. I haven't really found a way to
7370 * identify those yet, except for just looking at their duration. */
7371 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
7372 GST_WARNING_OBJECT (qtdemux,
7373 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
7374 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
7375 "found, assuming preview image or something; skipping track",
7376 stream->duration, stream->timescale, qtdemux->duration,
7377 qtdemux->timescale);
7383 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
7386 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
7387 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
7389 len = QT_UINT32 ((guint8 *) hdlr->data);
7391 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
7392 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
7393 GST_FOURCC_ARGS (stream->subtype));
7395 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
7398 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
7402 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
7404 stsd_data = (const guint8 *) stsd->data;
7406 /* stsd should at least have one entry */
7407 stsd_len = QT_UINT32 (stsd_data);
7408 if (stsd_len < 24) {
7409 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
7410 if (stream->subtype == FOURCC_vivo) {
7418 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
7420 /* and that entry should fit within stsd */
7421 len = QT_UINT32 (stsd_data + 16);
7422 if (len > stsd_len + 16)
7425 stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
7426 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
7427 GST_FOURCC_ARGS (stream->fourcc));
7428 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
7430 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi) ||
7431 ((fourcc & 0x00FFFFFF) == GST_MAKE_FOURCC ('e', 'n', 'c', 0)))
7432 goto error_encrypted;
7434 if (stream->subtype == FOURCC_vide) {
7435 guint32 w = 0, h = 0;
7437 gint depth, palette_size, palette_count;
7439 guint32 *palette_data = NULL;
7441 stream->sampled = TRUE;
7443 /* version 1 uses some 64-bit ints */
7444 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
7447 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
7450 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
7451 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
7454 stream->display_width = w >> 16;
7455 stream->display_height = h >> 16;
7457 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix, &list);
7463 stream->width = QT_UINT16 (stsd_data + offset + 32);
7464 stream->height = QT_UINT16 (stsd_data + offset + 34);
7465 stream->fps_n = 0; /* this is filled in later */
7466 stream->fps_d = 0; /* this is filled in later */
7467 stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
7468 stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
7470 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
7471 stream->width, stream->height, stream->bits_per_sample,
7472 stream->color_table_id);
7474 depth = stream->bits_per_sample;
7476 /* more than 32 bits means grayscale */
7477 gray = (depth > 32);
7478 /* low 32 bits specify the depth */
7481 /* different number of palette entries is determined by depth. */
7483 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
7484 palette_count = (1 << depth);
7485 palette_size = palette_count * 4;
7487 if (stream->color_table_id) {
7488 switch (palette_count) {
7492 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
7495 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
7499 palette_data = g_memdup (ff_qt_grayscale_palette_16, palette_size);
7501 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
7505 palette_data = g_memdup (ff_qt_grayscale_palette_256, palette_size);
7507 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
7510 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
7511 (_("The video in this file might not play correctly.")),
7512 ("unsupported palette depth %d", depth));
7516 gint i, j, start, end;
7522 start = QT_UINT32 (stsd_data + offset + 86);
7523 palette_count = QT_UINT16 (stsd_data + offset + 90);
7524 end = QT_UINT16 (stsd_data + offset + 92);
7526 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
7527 start, end, palette_count);
7534 if (len < 94 + (end - start) * 8)
7537 /* palette is always the same size */
7538 palette_data = g_malloc0 (256 * 4);
7539 palette_size = 256 * 4;
7541 for (j = 0, i = start; i <= end; j++, i++) {
7544 a = QT_UINT16 (stsd_data + offset + 94 + (j * 8));
7545 r = QT_UINT16 (stsd_data + offset + 96 + (j * 8));
7546 g = QT_UINT16 (stsd_data + offset + 98 + (j * 8));
7547 b = QT_UINT16 (stsd_data + offset + 100 + (j * 8));
7549 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
7550 (g & 0xff00) | (b >> 8);
7555 qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
7556 if (G_UNLIKELY (!stream->caps)) {
7557 g_free (palette_data);
7558 goto unknown_stream;
7563 list = gst_tag_list_new_empty ();
7564 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7565 GST_TAG_VIDEO_CODEC, codec, NULL);
7574 if (stream->rgb8_palette)
7575 gst_memory_unref (stream->rgb8_palette);
7576 stream->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
7577 palette_data, palette_size, 0, palette_size, palette_data, g_free);
7579 s = gst_caps_get_structure (stream->caps, 0);
7581 /* non-raw video has a palette_data property. raw video has the palette as
7582 * an extra plane that we append to the output buffers before we push
7584 if (!gst_structure_has_name (s, "video/x-raw")) {
7587 palette = gst_buffer_new ();
7588 gst_buffer_append_memory (palette, stream->rgb8_palette);
7589 stream->rgb8_palette = NULL;
7591 gst_caps_set_simple (stream->caps, "palette_data",
7592 GST_TYPE_BUFFER, palette, NULL);
7593 gst_buffer_unref (palette);
7595 } else if (palette_count != 0) {
7596 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
7597 (NULL), ("Unsupported palette depth %d", depth));
7600 GST_LOG_OBJECT (qtdemux, "frame count: %u",
7601 QT_UINT16 (stsd_data + offset + 48));
7605 /* pick 'the' stsd child */
7606 mp4v = qtdemux_tree_get_child_by_type (stsd, fourcc);
7608 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
7609 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
7613 const guint8 *pasp_data = (const guint8 *) pasp->data;
7615 stream->par_w = QT_UINT32 (pasp_data + 8);
7616 stream->par_h = QT_UINT32 (pasp_data + 12);
7623 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
7630 gint len = QT_UINT32 (stsd_data) - 0x66;
7631 const guint8 *avc_data = stsd_data + 0x66;
7634 while (len >= 0x8) {
7637 if (QT_UINT32 (avc_data) <= len)
7638 size = QT_UINT32 (avc_data) - 0x8;
7643 /* No real data, so break out */
7646 switch (QT_FOURCC (avc_data + 0x4)) {
7649 /* parse, if found */
7652 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
7654 /* First 4 bytes are the length of the atom, the next 4 bytes
7655 * are the fourcc, the next 1 byte is the version, and the
7656 * subsequent bytes are profile_tier_level structure like data. */
7657 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
7658 avc_data + 8 + 1, size - 1);
7659 buf = gst_buffer_new_and_alloc (size);
7660 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
7661 gst_caps_set_simple (stream->caps,
7662 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7663 gst_buffer_unref (buf);
7671 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
7673 /* First 4 bytes are the length of the atom, the next 4 bytes
7674 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
7675 * next 1 byte is the version, and the
7676 * subsequent bytes are sequence parameter set like data. */
7678 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
7680 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
7681 avc_data + 8 + 40 + 1, size - 1);
7683 buf = gst_buffer_new_and_alloc (size);
7684 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
7685 gst_caps_set_simple (stream->caps,
7686 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7687 gst_buffer_unref (buf);
7693 guint avg_bitrate, max_bitrate;
7695 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
7699 max_bitrate = QT_UINT32 (avc_data + 0xc);
7700 avg_bitrate = QT_UINT32 (avc_data + 0x10);
7702 if (!max_bitrate && !avg_bitrate)
7705 /* Some muxers seem to swap the average and maximum bitrates
7706 * (I'm looking at you, YouTube), so we swap for sanity. */
7707 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
7708 guint temp = avg_bitrate;
7710 avg_bitrate = max_bitrate;
7715 list = gst_tag_list_new_empty ();
7717 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
7718 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7719 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
7721 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
7722 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7723 GST_TAG_BITRATE, avg_bitrate, NULL);
7734 avc_data += size + 8;
7743 gint len = QT_UINT32 (stsd_data) - 0x66;
7744 const guint8 *hevc_data = stsd_data + 0x66;
7747 while (len >= 0x8) {
7750 if (QT_UINT32 (hevc_data) <= len)
7751 size = QT_UINT32 (hevc_data) - 0x8;
7756 /* No real data, so break out */
7759 switch (QT_FOURCC (hevc_data + 0x4)) {
7762 /* parse, if found */
7765 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
7767 /* First 4 bytes are the length of the atom, the next 4 bytes
7768 * are the fourcc, the next 1 byte is the version, and the
7769 * subsequent bytes are sequence parameter set like data. */
7770 gst_codec_utils_h265_caps_set_level_tier_and_profile
7771 (stream->caps, hevc_data + 8 + 1, size - 1);
7773 buf = gst_buffer_new_and_alloc (size);
7774 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
7775 gst_caps_set_simple (stream->caps,
7776 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7777 gst_buffer_unref (buf);
7784 hevc_data += size + 8;
7795 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
7796 GST_FOURCC_ARGS (fourcc));
7798 /* codec data might be in glbl extension atom */
7800 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
7806 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
7808 len = QT_UINT32 (data);
7811 buf = gst_buffer_new_and_alloc (len);
7812 gst_buffer_fill (buf, 0, data + 8, len);
7813 gst_caps_set_simple (stream->caps,
7814 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7815 gst_buffer_unref (buf);
7822 /* see annex I of the jpeg2000 spec */
7823 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
7825 const gchar *colorspace = NULL;
7827 guint32 ncomp_map = 0;
7828 gint32 *comp_map = NULL;
7829 guint32 nchan_def = 0;
7830 gint32 *chan_def = NULL;
7832 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
7833 /* some required atoms */
7834 mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
7837 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
7841 /* number of components; redundant with info in codestream, but useful
7843 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
7844 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
7846 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
7848 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
7851 GST_DEBUG_OBJECT (qtdemux, "found colr");
7852 /* extract colour space info */
7853 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
7854 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
7856 colorspace = "sRGB";
7859 colorspace = "GRAY";
7862 colorspace = "sYUV";
7870 /* colr is required, and only values 16, 17, and 18 are specified,
7871 so error if we have no colorspace */
7874 /* extract component mapping */
7875 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
7877 guint32 cmap_len = 0;
7879 cmap_len = QT_UINT32 (cmap->data);
7880 if (cmap_len >= 8) {
7881 /* normal box, subtract off header */
7883 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
7884 if (cmap_len % 4 == 0) {
7885 ncomp_map = (cmap_len / 4);
7886 comp_map = g_new0 (gint32, ncomp_map);
7887 for (i = 0; i < ncomp_map; i++) {
7890 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
7891 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
7892 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
7893 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
7898 /* extract channel definitions */
7899 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
7901 guint32 cdef_len = 0;
7903 cdef_len = QT_UINT32 (cdef->data);
7904 if (cdef_len >= 10) {
7905 /* normal box, subtract off header and len */
7907 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
7908 if (cdef_len % 6 == 0) {
7909 nchan_def = (cdef_len / 6);
7910 chan_def = g_new0 (gint32, nchan_def);
7911 for (i = 0; i < nchan_def; i++)
7913 for (i = 0; i < nchan_def; i++) {
7914 guint16 cn, typ, asoc;
7915 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
7916 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
7917 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
7918 if (cn < nchan_def) {
7921 chan_def[cn] = asoc;
7924 chan_def[cn] = 0; /* alpha */
7927 chan_def[cn] = -typ;
7935 gst_caps_set_simple (stream->caps,
7936 "num-components", G_TYPE_INT, ncomp, NULL);
7937 gst_caps_set_simple (stream->caps,
7938 "colorspace", G_TYPE_STRING, colorspace, NULL);
7941 GValue arr = { 0, };
7942 GValue elt = { 0, };
7944 g_value_init (&arr, GST_TYPE_ARRAY);
7945 g_value_init (&elt, G_TYPE_INT);
7946 for (i = 0; i < ncomp_map; i++) {
7947 g_value_set_int (&elt, comp_map[i]);
7948 gst_value_array_append_value (&arr, &elt);
7950 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
7951 "component-map", &arr);
7952 g_value_unset (&elt);
7953 g_value_unset (&arr);
7958 GValue arr = { 0, };
7959 GValue elt = { 0, };
7961 g_value_init (&arr, GST_TYPE_ARRAY);
7962 g_value_init (&elt, G_TYPE_INT);
7963 for (i = 0; i < nchan_def; i++) {
7964 g_value_set_int (&elt, chan_def[i]);
7965 gst_value_array_append_value (&arr, &elt);
7967 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
7968 "channel-definitions", &arr);
7969 g_value_unset (&elt);
7970 g_value_unset (&arr);
7974 /* some optional atoms */
7975 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
7976 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
7978 /* indicate possible fields in caps */
7980 data = (guint8 *) field->data + 8;
7982 gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
7983 (gint) * data, NULL);
7985 /* add codec_data if provided */
7990 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
7991 data = prefix->data;
7992 len = QT_UINT32 (data);
7995 buf = gst_buffer_new_and_alloc (len);
7996 gst_buffer_fill (buf, 0, data + 8, len);
7997 gst_caps_set_simple (stream->caps,
7998 "codec_data", GST_TYPE_BUFFER, buf, NULL);
7999 gst_buffer_unref (buf);
8008 GstBuffer *seqh = NULL;
8009 guint8 *gamma_data = NULL;
8010 gint len = QT_UINT32 (stsd_data);
8012 qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
8014 gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
8015 QT_FP32 (gamma_data), NULL);
8018 /* sorry for the bad name, but we don't know what this is, other
8019 * than its own fourcc */
8020 gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
8024 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
8025 buf = gst_buffer_new_and_alloc (len);
8026 gst_buffer_fill (buf, 0, stsd_data, len);
8027 gst_caps_set_simple (stream->caps,
8028 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8029 gst_buffer_unref (buf);
8035 gst_caps_set_simple (stream->caps,
8036 "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
8043 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
8044 xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
8048 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
8052 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
8053 /* collect the headers and store them in a stream list so that we can
8054 * send them out first */
8055 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
8065 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
8066 ovc1 = qtdemux_tree_get_child_by_type (stsd, FOURCC_ovc1);
8069 ovc1_data = ovc1->data;
8070 ovc1_len = QT_UINT32 (ovc1_data);
8071 if (ovc1_len <= 198) {
8072 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
8075 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
8076 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
8077 gst_caps_set_simple (stream->caps,
8078 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8079 gst_buffer_unref (buf);
8087 GST_INFO_OBJECT (qtdemux,
8088 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
8089 GST_FOURCC_ARGS (fourcc), stream->caps);
8091 } else if (stream->subtype == FOURCC_soun) {
8092 int version, samplesize;
8093 guint16 compression_id;
8094 gboolean amrwb = FALSE;
8097 /* sample description entry (16) + sound sample description v0 (20) */
8101 version = QT_UINT32 (stsd_data + offset);
8102 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
8103 samplesize = QT_UINT16 (stsd_data + offset + 10);
8104 compression_id = QT_UINT16 (stsd_data + offset + 12);
8105 stream->rate = QT_FP32 (stsd_data + offset + 16);
8107 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
8108 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
8109 QT_UINT32 (stsd_data + offset + 4));
8110 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
8111 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
8112 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
8113 GST_LOG_OBJECT (qtdemux, "packet size: %d",
8114 QT_UINT16 (stsd_data + offset + 14));
8115 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
8117 if (compression_id == 0xfffe)
8118 stream->sampled = TRUE;
8120 /* first assume uncompressed audio */
8121 stream->bytes_per_sample = samplesize / 8;
8122 stream->samples_per_frame = stream->n_channels;
8123 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
8124 stream->samples_per_packet = stream->samples_per_frame;
8125 stream->bytes_per_packet = stream->bytes_per_sample;
8129 /* Yes, these have to be hard-coded */
8132 stream->samples_per_packet = 6;
8133 stream->bytes_per_packet = 1;
8134 stream->bytes_per_frame = 1 * stream->n_channels;
8135 stream->bytes_per_sample = 1;
8136 stream->samples_per_frame = 6 * stream->n_channels;
8141 stream->samples_per_packet = 3;
8142 stream->bytes_per_packet = 1;
8143 stream->bytes_per_frame = 1 * stream->n_channels;
8144 stream->bytes_per_sample = 1;
8145 stream->samples_per_frame = 3 * stream->n_channels;
8150 stream->samples_per_packet = 64;
8151 stream->bytes_per_packet = 34;
8152 stream->bytes_per_frame = 34 * stream->n_channels;
8153 stream->bytes_per_sample = 2;
8154 stream->samples_per_frame = 64 * stream->n_channels;
8160 stream->samples_per_packet = 1;
8161 stream->bytes_per_packet = 1;
8162 stream->bytes_per_frame = 1 * stream->n_channels;
8163 stream->bytes_per_sample = 1;
8164 stream->samples_per_frame = 1 * stream->n_channels;
8169 stream->samples_per_packet = 160;
8170 stream->bytes_per_packet = 33;
8171 stream->bytes_per_frame = 33 * stream->n_channels;
8172 stream->bytes_per_sample = 2;
8173 stream->samples_per_frame = 160 * stream->n_channels;
8180 if (version == 0x00010000) {
8181 /* sample description entry (16) + sound sample description v1 (20+16) */
8192 /* only parse extra decoding config for non-pcm audio */
8193 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
8194 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
8195 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
8196 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
8198 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
8199 stream->samples_per_packet);
8200 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
8201 stream->bytes_per_packet);
8202 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
8203 stream->bytes_per_frame);
8204 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
8205 stream->bytes_per_sample);
8207 if (!stream->sampled && stream->bytes_per_packet) {
8208 stream->samples_per_frame = (stream->bytes_per_frame /
8209 stream->bytes_per_packet) * stream->samples_per_packet;
8210 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
8211 stream->samples_per_frame);
8216 } else if (version == 0x00020000) {
8223 /* sample description entry (16) + sound sample description v2 (56) */
8227 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
8228 stream->rate = qtfp.fp;
8229 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
8231 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
8232 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
8233 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
8234 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
8235 QT_UINT32 (stsd_data + offset + 20));
8236 GST_LOG_OBJECT (qtdemux, "format flags: %X",
8237 QT_UINT32 (stsd_data + offset + 24));
8238 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
8239 QT_UINT32 (stsd_data + offset + 28));
8240 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
8241 QT_UINT32 (stsd_data + offset + 32));
8243 GST_WARNING_OBJECT (qtdemux, "unknown version %08x", version);
8246 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc,
8247 stsd_data + 32, len - 16, &codec);
8255 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
8257 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
8259 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
8261 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
8264 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
8265 gst_caps_set_simple (stream->caps,
8266 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE", NULL);
8273 const guint8 *owma_data;
8274 const gchar *codec_name = NULL;
8278 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
8279 /* FIXME this should also be gst_riff_strf_auds,
8280 * but the latter one is actually missing bits-per-sample :( */
8285 gint32 nSamplesPerSec;
8286 gint32 nAvgBytesPerSec;
8288 gint16 wBitsPerSample;
8293 GST_DEBUG_OBJECT (qtdemux, "parse owma");
8294 owma = qtdemux_tree_get_child_by_type (stsd, FOURCC_owma);
8297 owma_data = owma->data;
8298 owma_len = QT_UINT32 (owma_data);
8299 if (owma_len <= 54) {
8300 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
8303 wfex = (WAVEFORMATEX *) (owma_data + 36);
8304 buf = gst_buffer_new_and_alloc (owma_len - 54);
8305 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
8306 if (wfex->wFormatTag == 0x0161) {
8307 codec_name = "Windows Media Audio";
8309 } else if (wfex->wFormatTag == 0x0162) {
8310 codec_name = "Windows Media Audio 9 Pro";
8312 } else if (wfex->wFormatTag == 0x0163) {
8313 codec_name = "Windows Media Audio 9 Lossless";
8314 /* is that correct? gstffmpegcodecmap.c is missing it, but
8315 * fluendo codec seems to support it */
8319 gst_caps_set_simple (stream->caps,
8320 "codec_data", GST_TYPE_BUFFER, buf,
8321 "wmaversion", G_TYPE_INT, version,
8322 "block_align", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->nBlockAlign),
8323 "bitrate", G_TYPE_INT, GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec),
8324 "width", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
8325 "depth", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
8327 gst_buffer_unref (buf);
8331 codec = g_strdup (codec_name);
8344 list = gst_tag_list_new_empty ();
8345 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
8346 GST_TAG_AUDIO_CODEC, codec, NULL);
8350 /* some bitrate info may have ended up in caps */
8351 s = gst_caps_get_structure (stream->caps, 0);
8352 gst_structure_get_int (s, "bitrate", &bitrate);
8354 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
8358 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
8362 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
8364 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
8366 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
8370 /* If the fourcc's bottom 16 bits gives 'sm', then the top
8371 16 bits is a byte-swapped wave-style codec identifier,
8372 and we can find a WAVE header internally to a 'wave' atom here.
8373 This can more clearly be thought of as 'ms' as the top 16 bits, and a
8374 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
8377 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
8378 if (len < offset + 20) {
8379 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
8381 guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
8382 const guint8 *data = stsd_data + offset + 16;
8384 GNode *waveheadernode;
8386 wavenode = g_node_new ((guint8 *) data);
8387 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
8388 const guint8 *waveheader;
8391 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
8392 if (waveheadernode) {
8393 waveheader = (const guint8 *) waveheadernode->data;
8394 headerlen = QT_UINT32 (waveheader);
8396 if (headerlen > 8) {
8397 gst_riff_strf_auds *header = NULL;
8398 GstBuffer *headerbuf;
8404 headerbuf = gst_buffer_new_and_alloc (headerlen);
8405 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
8407 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
8408 headerbuf, &header, &extra)) {
8409 gst_caps_unref (stream->caps);
8410 /* FIXME: Need to do something with the channel reorder map */
8411 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
8412 header, extra, NULL, NULL, NULL);
8415 gst_buffer_unref (extra);
8420 GST_DEBUG ("Didn't find waveheadernode for this codec");
8422 g_node_destroy (wavenode);
8425 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
8429 /* FIXME: what is in the chunk? */
8432 gint len = QT_UINT32 (stsd_data);
8434 /* seems to be always = 116 = 0x74 */
8440 gint len = QT_UINT32 (stsd_data);
8443 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
8445 gst_buffer_fill (buf, 0, stsd_data + 0x4C, len - 0x4C);
8446 gst_caps_set_simple (stream->caps,
8447 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8448 gst_buffer_unref (buf);
8450 gst_caps_set_simple (stream->caps,
8451 "samplesize", G_TYPE_INT, samplesize, NULL);
8456 GNode *alac, *wave = NULL;
8458 /* apparently, m4a has this atom appended directly in the stsd entry,
8459 * while mov has it in a wave atom */
8460 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
8462 /* alac now refers to stsd entry atom */
8463 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
8465 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
8467 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
8470 const guint8 *alac_data = alac->data;
8471 gint len = QT_UINT32 (alac->data);
8475 GST_DEBUG_OBJECT (qtdemux,
8476 "discarding alac atom with unexpected len %d", len);
8478 /* codec-data contains alac atom size and prefix,
8479 * ffmpeg likes it that way, not quite gst-ish though ...*/
8480 buf = gst_buffer_new_and_alloc (len);
8481 gst_buffer_fill (buf, 0, alac->data, len);
8482 gst_caps_set_simple (stream->caps,
8483 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8484 gst_buffer_unref (buf);
8486 stream->bytes_per_frame = QT_UINT32 (alac_data + 12);
8487 stream->n_channels = QT_UINT8 (alac_data + 21);
8488 stream->rate = QT_UINT32 (alac_data + 32);
8491 gst_caps_set_simple (stream->caps,
8492 "samplesize", G_TYPE_INT, samplesize, NULL);
8500 gint len = QT_UINT32 (stsd_data);
8503 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
8506 gst_buffer_fill (buf, 0, stsd_data + 0x34, len - 0x34);
8508 /* If we have enough data, let's try to get the 'damr' atom. See
8509 * the 3GPP container spec (26.244) for more details. */
8510 if ((len - 0x34) > 8 &&
8511 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
8513 list = gst_tag_list_new_empty ();
8514 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
8515 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
8518 gst_caps_set_simple (stream->caps,
8519 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8520 gst_buffer_unref (buf);
8525 GST_INFO_OBJECT (qtdemux,
8526 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
8530 GST_INFO_OBJECT (qtdemux,
8531 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
8532 GST_FOURCC_ARGS (fourcc), stream->caps);
8534 } else if (stream->subtype == FOURCC_strm) {
8535 if (fourcc == FOURCC_rtsp) {
8536 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
8538 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
8539 GST_FOURCC_ARGS (fourcc));
8540 goto unknown_stream;
8542 stream->sampled = TRUE;
8543 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
8544 || stream->subtype == FOURCC_sbtl) {
8546 stream->sampled = TRUE;
8547 stream->sparse = TRUE;
8552 qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
8554 list = gst_tag_list_new_empty ();
8555 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
8556 GST_TAG_SUBTITLE_CODEC, codec, NULL);
8561 /* hunt for sort-of codec data */
8568 /* look for palette in a stsd->mp4s->esds sub-atom */
8569 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
8571 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
8574 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
8578 gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
8582 GST_INFO_OBJECT (qtdemux,
8583 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
8586 GST_INFO_OBJECT (qtdemux,
8587 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
8588 GST_FOURCC_ARGS (fourcc), stream->caps);
8590 /* everything in 1 sample */
8591 stream->sampled = TRUE;
8594 qtdemux_generic_caps (qtdemux, stream, fourcc, stsd_data, &codec);
8596 if (stream->caps == NULL)
8597 goto unknown_stream;
8600 list = gst_tag_list_new_empty ();
8601 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
8602 GST_TAG_SUBTITLE_CODEC, codec, NULL);
8608 /* promote to sampled format */
8609 if (stream->fourcc == FOURCC_samr) {
8610 /* force mono 8000 Hz for AMR */
8611 stream->sampled = TRUE;
8612 stream->n_channels = 1;
8613 stream->rate = 8000;
8614 } else if (stream->fourcc == FOURCC_sawb) {
8615 /* force mono 16000 Hz for AMR-WB */
8616 stream->sampled = TRUE;
8617 stream->n_channels = 1;
8618 stream->rate = 16000;
8619 } else if (stream->fourcc == FOURCC_mp4a) {
8620 stream->sampled = TRUE;
8623 /* collect sample information */
8624 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
8625 goto samples_failed;
8627 if (qtdemux->fragmented) {
8631 /* need all moov samples as basis; probably not many if any at all */
8632 /* prevent moof parsing taking of at this time */
8633 offset = qtdemux->moof_offset;
8634 qtdemux->moof_offset = 0;
8635 if (stream->n_samples &&
8636 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
8637 qtdemux->moof_offset = offset;
8638 goto samples_failed;
8640 qtdemux->moof_offset = 0;
8641 /* movie duration more reliable in this case (e.g. mehd) */
8642 if (qtdemux->segment.duration &&
8643 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
8644 stream->duration = gst_util_uint64_scale (qtdemux->segment.duration,
8645 stream->timescale, GST_SECOND);
8646 /* need defaults for fragments */
8647 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
8650 /* configure segments */
8651 if (!qtdemux_parse_segments (qtdemux, stream, trak))
8652 goto segments_failed;
8654 /* add some language tag, if useful */
8655 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
8656 strcmp (stream->lang_id, "und")) {
8657 const gchar *lang_code;
8660 list = gst_tag_list_new_empty ();
8662 /* convert ISO 639-2 code to ISO 639-1 */
8663 lang_code = gst_tag_get_language_code (stream->lang_id);
8664 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
8665 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
8668 /* now we are ready to add the stream */
8669 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
8670 goto too_many_streams;
8672 if (!qtdemux->got_moov) {
8673 stream->pending_tags = list;
8674 qtdemux->streams[qtdemux->n_streams] = stream;
8675 qtdemux->n_streams++;
8676 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
8684 GST_INFO_OBJECT (qtdemux, "skip disabled track");
8691 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8692 (_("This file is corrupt and cannot be played.")), (NULL));
8699 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
8707 /* we posted an error already */
8708 /* free stbl sub-atoms */
8709 gst_qtdemux_stbl_free (stream);
8716 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
8724 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
8725 GST_FOURCC_ARGS (stream->subtype));
8732 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
8733 (_("This file contains too many streams. Only playing first %d"),
8734 GST_QTDEMUX_MAX_STREAMS), (NULL));
8739 /* If we can estimate the overall bitrate, and don't have information about the
8740 * stream bitrate for exactly one stream, this guesses the stream bitrate as
8741 * the overall bitrate minus the sum of the bitrates of all other streams. This
8742 * should be useful for the common case where we have one audio and one video
8743 * stream and can estimate the bitrate of one, but not the other. */
8745 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
8747 QtDemuxStream *stream = NULL;
8748 gint64 size, duration, sys_bitrate, sum_bitrate = 0;
8752 if (qtdemux->fragmented)
8755 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
8757 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
8759 GST_DEBUG_OBJECT (qtdemux,
8760 "Size in bytes of the stream not known - bailing");
8764 /* Subtract the header size */
8765 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
8766 size, qtdemux->header_size);
8768 if (size < qtdemux->header_size)
8771 size = size - qtdemux->header_size;
8773 if (!gst_qtdemux_get_duration (qtdemux, &duration) ||
8774 duration == GST_CLOCK_TIME_NONE) {
8775 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
8779 for (i = 0; i < qtdemux->n_streams; i++) {
8780 switch (qtdemux->streams[i]->subtype) {
8783 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
8784 qtdemux->streams[i]->caps);
8785 /* retrieve bitrate, prefer avg then max */
8787 if (qtdemux->streams[i]->pending_tags) {
8788 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
8789 GST_TAG_MAXIMUM_BITRATE, &bitrate);
8790 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
8791 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
8792 GST_TAG_NOMINAL_BITRATE, &bitrate);
8793 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
8794 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
8795 GST_TAG_BITRATE, &bitrate);
8796 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
8799 sum_bitrate += bitrate;
8802 GST_DEBUG_OBJECT (qtdemux,
8803 ">1 stream with unknown bitrate - bailing");
8806 stream = qtdemux->streams[i];
8810 /* For other subtypes, we assume no significant impact on bitrate */
8816 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
8820 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
8822 if (sys_bitrate < sum_bitrate) {
8823 /* This can happen, since sum_bitrate might be derived from maximum
8824 * bitrates and not average bitrates */
8825 GST_DEBUG_OBJECT (qtdemux,
8826 "System bitrate less than sum bitrate - bailing");
8830 bitrate = sys_bitrate - sum_bitrate;
8831 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
8832 ", Stream bitrate = %u", sys_bitrate, bitrate);
8834 if (!stream->pending_tags)
8835 stream->pending_tags = gst_tag_list_new_empty ();
8837 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
8838 GST_TAG_BITRATE, bitrate, NULL);
8841 static GstFlowReturn
8842 qtdemux_prepare_streams (GstQTDemux * qtdemux)
8845 GstFlowReturn ret = GST_FLOW_OK;
8847 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
8849 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
8850 QtDemuxStream *stream = qtdemux->streams[i];
8851 guint32 sample_num = 0;
8855 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
8856 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
8858 if (qtdemux->fragmented) {
8859 /* need all moov samples first */
8860 GST_OBJECT_LOCK (qtdemux);
8861 while (stream->n_samples == 0)
8862 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
8864 GST_OBJECT_UNLOCK (qtdemux);
8866 /* discard any stray moof */
8867 qtdemux->moof_offset = 0;
8870 /* prepare braking */
8871 if (ret != GST_FLOW_ERROR)
8874 /* in pull mode, we should have parsed some sample info by now;
8875 * and quite some code will not handle no samples.
8876 * in push mode, we'll just have to deal with it */
8877 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
8878 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
8879 gst_qtdemux_remove_stream (qtdemux, i);
8884 /* parse number of initial sample to set frame rate cap */
8885 while (sample_num < stream->n_samples && sample_num < samples) {
8886 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
8890 /* collect and sort durations */
8891 samples = MIN (stream->stbl_index + 1, samples);
8892 GST_DEBUG_OBJECT (qtdemux, "%d samples for framerate", samples);
8894 durations = g_array_sized_new (FALSE, FALSE, sizeof (guint32), samples);
8896 while (sample_num < samples) {
8897 g_array_append_val (durations, stream->samples[sample_num].duration);
8900 g_array_sort (durations, less_than);
8901 stream->min_duration = g_array_index (durations, guint32, samples / 2);
8902 g_array_free (durations, TRUE);
8909 static GstFlowReturn
8910 qtdemux_expose_streams (GstQTDemux * qtdemux)
8913 GstFlowReturn ret = GST_FLOW_OK;
8914 GSList *oldpads = NULL;
8917 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
8919 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
8920 QtDemuxStream *stream = qtdemux->streams[i];
8921 GstPad *oldpad = stream->pad;
8924 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
8925 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
8927 if ((stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl) &&
8928 stream->track_id == qtdemux->chapters_track_id) {
8929 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
8930 so that it doesn't look like a subtitle track */
8931 gst_qtdemux_remove_stream (qtdemux, i);
8936 /* now we have all info and can expose */
8937 list = stream->pending_tags;
8938 stream->pending_tags = NULL;
8940 oldpads = g_slist_prepend (oldpads, oldpad);
8941 gst_qtdemux_add_stream (qtdemux, stream, list);
8944 gst_qtdemux_guess_bitrate (qtdemux);
8946 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
8948 for (iter = oldpads; iter; iter = g_slist_next (iter)) {
8949 GstPad *oldpad = iter->data;
8951 gst_pad_push_event (oldpad, gst_event_new_eos ());
8952 gst_pad_set_active (oldpad, FALSE);
8953 gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
8954 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, oldpad);
8955 gst_object_unref (oldpad);
8958 /* check if we should post a redirect in case there is a single trak
8959 * and it is a redirecting trak */
8960 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
8963 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
8964 "an external content");
8965 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
8966 gst_structure_new ("redirect",
8967 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
8969 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
8970 qtdemux->posted_redirect = TRUE;
8973 for (i = 0; i < qtdemux->n_streams; i++) {
8974 QtDemuxStream *stream = qtdemux->streams[i];
8976 qtdemux_do_allocation (qtdemux, stream);
8979 qtdemux->exposed = TRUE;
8983 /* check if major or compatible brand is 3GP */
8984 static inline gboolean
8985 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
8988 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
8989 GST_MAKE_FOURCC ('3', 'g', 0, 0));
8990 } else if (qtdemux->comp_brands != NULL) {
8994 gboolean res = FALSE;
8996 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
9000 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
9001 GST_MAKE_FOURCC ('3', 'g', 0, 0));
9005 gst_buffer_unmap (qtdemux->comp_brands, &map);
9012 /* check if tag is a spec'ed 3GP tag keyword storing a string */
9013 static inline gboolean
9014 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
9016 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
9017 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
9018 || fourcc == FOURCC_albm;
9022 qtdemux_tag_add_location (GstQTDemux * qtdemux, const char *tag,
9023 const char *dummy, GNode * node)
9025 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
9029 gdouble longitude, latitude, altitude;
9032 len = QT_UINT32 (node->data);
9039 /* TODO: language code skipped */
9041 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
9044 /* do not alarm in trivial case, but bail out otherwise */
9045 if (*(data + offset) != 0) {
9046 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
9050 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9051 GST_TAG_GEO_LOCATION_NAME, name, NULL);
9052 offset += strlen (name);
9056 if (len < offset + 2 + 4 + 4 + 4)
9059 /* +1 +1 = skip null-terminator and location role byte */
9061 /* table in spec says unsigned, semantics say negative has meaning ... */
9062 longitude = QT_SFP32 (data + offset);
9065 latitude = QT_SFP32 (data + offset);
9068 altitude = QT_SFP32 (data + offset);
9070 /* one invalid means all are invalid */
9071 if (longitude >= -180.0 && longitude <= 180.0 &&
9072 latitude >= -90.0 && latitude <= 90.0) {
9073 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9074 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
9075 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
9076 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
9079 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
9086 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
9093 qtdemux_tag_add_year (GstQTDemux * qtdemux, const char *tag, const char *dummy,
9100 len = QT_UINT32 (node->data);
9104 y = QT_UINT16 ((guint8 *) node->data + 12);
9106 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
9109 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
9111 date = g_date_new_dmy (1, 1, y);
9112 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, date, NULL);
9117 qtdemux_tag_add_classification (GstQTDemux * qtdemux, const char *tag,
9118 const char *dummy, GNode * node)
9121 char *tag_str = NULL;
9126 len = QT_UINT32 (node->data);
9131 entity = (guint8 *) node->data + offset;
9132 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
9133 GST_DEBUG_OBJECT (qtdemux,
9134 "classification info: %c%c%c%c invalid classification entity",
9135 entity[0], entity[1], entity[2], entity[3]);
9140 table = QT_UINT16 ((guint8 *) node->data + offset);
9142 /* Language code skipped */
9146 /* Tag format: "XXXX://Y[YYYY]/classification info string"
9147 * XXXX: classification entity, fixed length 4 chars.
9148 * Y[YYYY]: classification table, max 5 chars.
9150 tag_str = g_strdup_printf ("----://%u/%s",
9151 table, (char *) node->data + offset);
9153 /* memcpy To be sure we're preserving byte order */
9154 memcpy (tag_str, entity, 4);
9155 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
9157 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_APPEND, tag,
9167 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
9173 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, const char *tag,
9174 const char *dummy, GNode * node)
9176 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
9182 gboolean ret = TRUE;
9183 const gchar *charset = NULL;
9185 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9187 len = QT_UINT32 (data->data);
9188 type = QT_UINT32 ((guint8 *) data->data + 8);
9189 if (type == 0x00000001 && len > 16) {
9190 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
9193 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
9194 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s,
9198 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
9202 len = QT_UINT32 (node->data);
9203 type = QT_UINT32 ((guint8 *) node->data + 4);
9204 if ((type >> 24) == 0xa9) {
9208 /* Type starts with the (C) symbol, so the next data is a list
9209 * of (string size(16), language code(16), string) */
9211 str_len = QT_UINT16 ((guint8 *) node->data + 8);
9212 lang_code = QT_UINT16 ((guint8 *) node->data + 10);
9214 /* the string + fourcc + size + 2 16bit fields,
9215 * means that there are more tags in this atom */
9216 if (len > str_len + 8 + 4) {
9217 /* TODO how to represent the same tag in different languages? */
9218 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
9219 "text alternatives, reading only first one");
9223 len = str_len + 8 + 4; /* remove trailing strings that we don't use */
9224 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
9226 if (lang_code < 0x800) { /* MAC encoded string */
9229 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
9230 QT_FOURCC ((guint8 *) node->data + 4))) {
9231 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
9233 /* we go for 3GP style encoding if major brands claims so,
9234 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
9235 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
9236 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
9237 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
9239 /* 16-bit Language code is ignored here as well */
9240 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
9247 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
9248 ret = FALSE; /* may have to fallback */
9253 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
9254 charset, NULL, NULL, &err);
9256 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
9257 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
9262 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
9263 len - offset, env_vars);
9266 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
9267 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s, NULL);
9271 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
9278 qtdemux_tag_add_str (GstQTDemux * qtdemux, const char *tag,
9279 const char *dummy, GNode * node)
9281 qtdemux_tag_add_str_full (qtdemux, tag, dummy, node);
9285 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, const char *tag,
9286 const char *dummy, GNode * node)
9288 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
9290 char *s, *t, *k = NULL;
9295 /* first try normal string tag if major brand not 3GP */
9296 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
9297 if (!qtdemux_tag_add_str_full (qtdemux, tag, dummy, node)) {
9298 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
9299 * let's try it 3gpp way after minor safety check */
9301 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
9307 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
9311 len = QT_UINT32 (data);
9315 count = QT_UINT8 (data + 14);
9317 for (; count; count--) {
9320 if (offset + 1 > len)
9322 slen = QT_UINT8 (data + offset);
9324 if (offset + slen > len)
9326 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
9329 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
9331 t = g_strjoin (",", k, s, NULL);
9339 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
9346 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
9347 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, k, NULL);
9356 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
9362 qtdemux_tag_add_num (GstQTDemux * qtdemux, const char *tag1,
9363 const char *tag2, GNode * node)
9370 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9372 len = QT_UINT32 (data->data);
9373 type = QT_UINT32 ((guint8 *) data->data + 8);
9374 if (type == 0x00000000 && len >= 22) {
9375 n1 = QT_UINT16 ((guint8 *) data->data + 18);
9376 n2 = QT_UINT16 ((guint8 *) data->data + 20);
9378 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
9379 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9383 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
9384 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9392 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
9400 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9402 len = QT_UINT32 (data->data);
9403 type = QT_UINT32 ((guint8 *) data->data + 8);
9404 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
9405 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
9406 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
9407 n1 = QT_UINT16 ((guint8 *) data->data + 16);
9409 /* do not add bpm=0 */
9410 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
9411 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9412 tag1, (gdouble) n1, NULL);
9419 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, const char *tag1,
9420 const char *dummy, GNode * node)
9427 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9429 len = QT_UINT32 (data->data);
9430 type = QT_UINT32 ((guint8 *) data->data + 8);
9431 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
9432 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
9433 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
9434 num = QT_UINT32 ((guint8 *) data->data + 16);
9436 /* do not add num=0 */
9437 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
9438 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9446 qtdemux_tag_add_covr (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
9454 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9456 len = QT_UINT32 (data->data);
9457 type = QT_UINT32 ((guint8 *) data->data + 8);
9458 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
9459 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
9461 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
9462 len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
9463 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
9464 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9465 tag1, sample, NULL);
9466 gst_sample_unref (sample);
9473 qtdemux_tag_add_date (GstQTDemux * qtdemux, const char *tag, const char *dummy,
9481 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9483 len = QT_UINT32 (data->data);
9484 type = QT_UINT32 ((guint8 *) data->data + 8);
9485 if (type == 0x00000001 && len > 16) {
9486 guint y, m = 1, d = 1;
9489 s = g_strndup ((char *) data->data + 16, len - 16);
9490 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
9491 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
9492 if (ret >= 1 && y > 1500 && y < 3000) {
9495 date = g_date_new_dmy (d, m, y);
9496 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag,
9500 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
9508 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, const char *tag, const char *dummy,
9513 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9515 /* re-route to normal string tag if major brand says so
9516 * or no data atom and compatible brand suggests so */
9517 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
9518 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
9519 qtdemux_tag_add_str (qtdemux, tag, dummy, node);
9526 len = QT_UINT32 (data->data);
9527 type = QT_UINT32 ((guint8 *) data->data + 8);
9528 if (type == 0x00000000 && len >= 18) {
9529 n = QT_UINT16 ((guint8 *) data->data + 16);
9533 genre = gst_tag_id3_genre_get (n - 1);
9534 if (genre != NULL) {
9535 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
9536 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9545 qtdemux_add_double_tag_from_str (GstQTDemux * demux, const gchar * tag,
9546 guint8 * data, guint32 datasize)
9551 /* make a copy to have \0 at the end */
9552 datacopy = g_strndup ((gchar *) data, datasize);
9554 /* convert the str to double */
9555 if (sscanf (datacopy, "%lf", &value) == 1) {
9556 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
9557 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_REPLACE, tag, value, NULL);
9559 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
9567 qtdemux_tag_add_revdns (GstQTDemux * demux, const char *tag,
9568 const char *tag_bis, GNode * node)
9577 const gchar *meanstr;
9578 const gchar *namestr;
9580 /* checking the whole ---- atom size for consistency */
9581 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
9582 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
9586 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
9588 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
9592 meansize = QT_UINT32 (mean->data);
9593 if (meansize <= 12) {
9594 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
9597 meanstr = ((gchar *) mean->data) + 12;
9600 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
9602 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
9606 namesize = QT_UINT32 (name->data);
9607 if (namesize <= 12) {
9608 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
9611 namestr = ((gchar *) name->data) + 12;
9619 * uint24 - data type
9623 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9625 GST_WARNING_OBJECT (demux, "No data atom in this tag");
9628 datasize = QT_UINT32 (data->data);
9629 if (datasize <= 16) {
9630 GST_WARNING_OBJECT (demux, "Data atom too small");
9633 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
9635 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
9636 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
9639 const gchar name[28];
9640 const gchar tag[28];
9643 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
9644 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
9645 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
9646 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
9647 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
9648 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
9649 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
9650 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
9654 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
9655 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
9656 switch (gst_tag_get_type (tags[i].tag)) {
9658 qtdemux_add_double_tag_from_str (demux, tags[i].tag,
9659 ((guint8 *) data->data) + 16, datasize - 16);
9662 qtdemux_tag_add_str (demux, tags[i].tag, NULL, node);
9671 if (i == G_N_ELEMENTS (tags))
9681 #ifndef GST_DISABLE_GST_DEBUG
9686 meanstr_dbg = g_strndup (meanstr, meansize);
9687 namestr_dbg = g_strndup (namestr, namesize);
9689 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
9690 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
9692 g_free (namestr_dbg);
9693 g_free (meanstr_dbg);
9700 qtdemux_tag_add_id32 (GstQTDemux * demux, const char *tag,
9701 const char *tag_bis, GNode * node)
9706 GstTagList *taglist = NULL;
9708 GST_LOG_OBJECT (demux, "parsing ID32");
9711 len = GST_READ_UINT32_BE (data);
9713 /* need at least full box and language tag */
9717 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
9718 gst_buffer_fill (buf, 0, data + 14, len - 14);
9720 taglist = gst_tag_list_from_id3v2_tag (buf);
9722 GST_LOG_OBJECT (demux, "parsing ok");
9723 gst_tag_list_insert (demux->tag_list, taglist, GST_TAG_MERGE_KEEP);
9725 GST_LOG_OBJECT (demux, "parsing failed");
9729 gst_tag_list_unref (taglist);
9731 gst_buffer_unref (buf);
9734 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux,
9735 const char *tag, const char *tag_bis, GNode * node);
9738 FOURCC_pcst -> if media is a podcast -> bool
9739 FOURCC_cpil -> if media is part of a compilation -> bool
9740 FOURCC_pgap -> if media is part of a gapless context -> bool
9741 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
9747 const gchar *gst_tag;
9748 const gchar *gst_tag_bis;
9749 const GstQTDemuxAddTagFunc func;
9752 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
9753 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
9754 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
9755 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
9756 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
9757 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
9758 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
9759 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
9760 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
9761 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
9762 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
9763 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
9764 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
9765 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
9766 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
9767 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
9768 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
9769 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
9770 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
9771 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
9772 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
9773 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
9774 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
9775 qtdemux_tag_add_num}, {
9776 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
9777 qtdemux_tag_add_num}, {
9778 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
9779 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
9780 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
9781 FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
9782 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
9783 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
9784 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
9785 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
9786 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
9787 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
9788 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
9789 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
9790 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
9791 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
9792 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
9793 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
9794 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
9795 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
9796 qtdemux_tag_add_classification}, {
9797 FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
9798 FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
9799 FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
9801 /* This is a special case, some tags are stored in this
9802 * 'reverse dns naming', according to:
9803 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
9806 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
9807 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
9808 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
9812 qtdemux_tag_add_blob (GNode * node, GstQTDemux * demux)
9825 len = QT_UINT32 (data);
9826 buf = gst_buffer_new_and_alloc (len);
9827 gst_buffer_fill (buf, 0, data, len);
9829 /* heuristic to determine style of tag */
9830 if (QT_FOURCC (data + 4) == FOURCC_____ ||
9831 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
9833 else if (demux->major_brand == FOURCC_qt__)
9834 style = "quicktime";
9835 /* fall back to assuming iso/3gp tag style */
9839 /* santize the name for the caps. */
9840 for (i = 0; i < 4; i++) {
9841 guint8 d = data[4 + i];
9842 if (g_ascii_isalnum (d))
9843 ndata[i] = g_ascii_tolower (d);
9848 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
9849 ndata[0], ndata[1], ndata[2], ndata[3]);
9850 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
9852 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
9853 sample = gst_sample_new (buf, NULL, NULL, s);
9854 gst_buffer_unref (buf);
9855 g_free (media_type);
9857 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
9860 gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_APPEND,
9861 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
9863 gst_sample_unref (sample);
9867 qtdemux_parse_udta (GstQTDemux * qtdemux, GNode * udta)
9875 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
9877 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
9879 GST_LOG_OBJECT (qtdemux, "no ilst");
9884 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
9887 GST_DEBUG_OBJECT (qtdemux, "new tag list");
9888 if (!qtdemux->tag_list) {
9889 qtdemux->tag_list = gst_tag_list_new_empty ();
9890 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
9892 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
9896 while (i < G_N_ELEMENTS (add_funcs)) {
9897 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
9901 len = QT_UINT32 (node->data);
9903 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
9904 GST_FOURCC_ARGS (add_funcs[i].fourcc));
9906 add_funcs[i].func (qtdemux, add_funcs[i].gst_tag,
9907 add_funcs[i].gst_tag_bis, node);
9909 g_node_destroy (node);
9915 /* parsed nodes have been removed, pass along remainder as blob */
9916 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
9917 (GNodeForeachFunc) qtdemux_tag_add_blob, qtdemux);
9919 /* parse up XMP_ node if existing */
9920 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
9923 GstTagList *taglist;
9925 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
9926 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
9927 taglist = gst_tag_list_from_xmp_buffer (buf);
9928 gst_buffer_unref (buf);
9930 qtdemux_handle_xmp_taglist (qtdemux, taglist);
9932 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
9939 GstStructure *structure; /* helper for sort function */
9941 guint min_req_bitrate;
9942 guint min_req_qt_version;
9946 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
9948 GstQtReference *ref_a = (GstQtReference *) a;
9949 GstQtReference *ref_b = (GstQtReference *) b;
9951 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
9952 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
9954 /* known bitrates go before unknown; higher bitrates go first */
9955 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
9958 /* sort the redirects and post a message for the application.
9961 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
9963 GstQtReference *best;
9966 GValue list_val = { 0, };
9969 g_assert (references != NULL);
9971 references = g_list_sort (references, qtdemux_redirects_sort_func);
9973 best = (GstQtReference *) references->data;
9975 g_value_init (&list_val, GST_TYPE_LIST);
9977 for (l = references; l != NULL; l = l->next) {
9978 GstQtReference *ref = (GstQtReference *) l->data;
9979 GValue struct_val = { 0, };
9981 ref->structure = gst_structure_new ("redirect",
9982 "new-location", G_TYPE_STRING, ref->location, NULL);
9984 if (ref->min_req_bitrate > 0) {
9985 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
9986 ref->min_req_bitrate, NULL);
9989 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
9990 g_value_set_boxed (&struct_val, ref->structure);
9991 gst_value_list_append_value (&list_val, &struct_val);
9992 g_value_unset (&struct_val);
9993 /* don't free anything here yet, since we need best->structure below */
9996 g_assert (best != NULL);
9997 s = gst_structure_copy (best->structure);
9999 if (g_list_length (references) > 1) {
10000 gst_structure_set_value (s, "locations", &list_val);
10003 g_value_unset (&list_val);
10005 for (l = references; l != NULL; l = l->next) {
10006 GstQtReference *ref = (GstQtReference *) l->data;
10008 gst_structure_free (ref->structure);
10009 g_free (ref->location);
10012 g_list_free (references);
10014 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
10015 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
10016 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
10017 qtdemux->posted_redirect = TRUE;
10020 /* look for redirect nodes, collect all redirect information and
10024 qtdemux_parse_redirects (GstQTDemux * qtdemux)
10026 GNode *rmra, *rmda, *rdrf;
10028 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
10030 GList *redirects = NULL;
10032 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
10034 GstQtReference ref = { NULL, NULL, 0, 0 };
10035 GNode *rmdr, *rmvc;
10037 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
10038 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
10039 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
10040 ref.min_req_bitrate);
10043 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
10044 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
10045 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
10047 #ifndef GST_DISABLE_GST_DEBUG
10048 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
10050 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
10052 GST_LOG_OBJECT (qtdemux,
10053 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
10054 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
10055 bitmask, check_type);
10056 if (package == FOURCC_qtim && check_type == 0) {
10057 ref.min_req_qt_version = version;
10061 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
10066 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
10067 ref_data = (guint8 *) rdrf->data + 20;
10068 if (ref_type == FOURCC_alis) {
10069 guint record_len, record_version, fn_len;
10071 /* MacOSX alias record, google for alias-layout.txt */
10072 record_len = QT_UINT16 (ref_data + 4);
10073 record_version = QT_UINT16 (ref_data + 4 + 2);
10074 fn_len = QT_UINT8 (ref_data + 50);
10075 if (record_len > 50 && record_version == 2 && fn_len > 0) {
10076 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
10078 } else if (ref_type == FOURCC_url_) {
10079 ref.location = g_strdup ((gchar *) ref_data);
10081 GST_DEBUG_OBJECT (qtdemux,
10082 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
10083 GST_FOURCC_ARGS (ref_type));
10085 if (ref.location != NULL) {
10086 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
10087 redirects = g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
10089 GST_WARNING_OBJECT (qtdemux,
10090 "Failed to extract redirect location from rdrf atom");
10094 /* look for others */
10095 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
10098 if (redirects != NULL) {
10099 qtdemux_process_redirects (qtdemux, redirects);
10105 static GstTagList *
10106 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
10110 if (tags == NULL) {
10111 tags = gst_tag_list_new_empty ();
10112 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
10115 if (qtdemux->major_brand == FOURCC_mjp2)
10116 fmt = "Motion JPEG 2000";
10117 else if ((qtdemux->major_brand & 0xffff) == GST_MAKE_FOURCC ('3', 'g', 0, 0))
10119 else if (qtdemux->major_brand == FOURCC_qt__)
10121 else if (qtdemux->fragmented)
10124 fmt = "ISO MP4/M4A";
10126 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
10127 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
10129 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
10135 /* we have read th complete moov node now.
10136 * This function parses all of the relevant info, creates the traks and
10137 * prepares all data structures for playback
10140 qtdemux_parse_tree (GstQTDemux * qtdemux)
10147 guint64 creation_time;
10148 GstDateTime *datetime = NULL;
10151 /* make sure we have a usable taglist */
10152 if (!qtdemux->tag_list) {
10153 qtdemux->tag_list = gst_tag_list_new_empty ();
10154 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
10156 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
10159 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
10160 if (mvhd == NULL) {
10161 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
10162 return qtdemux_parse_redirects (qtdemux);
10165 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
10166 if (version == 1) {
10167 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
10168 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
10169 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
10170 } else if (version == 0) {
10171 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
10172 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
10173 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
10175 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
10179 /* Moving qt creation time (secs since 1904) to unix time */
10180 if (creation_time != 0) {
10181 /* Try to use epoch first as it should be faster and more commonly found */
10182 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
10185 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
10186 /* some data cleansing sanity */
10187 g_get_current_time (&now);
10188 if (now.tv_sec + 24 * 3600 < creation_time) {
10189 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
10191 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
10194 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
10195 GDateTime *dt, *dt_local;
10197 dt = g_date_time_add_seconds (base_dt, creation_time);
10198 dt_local = g_date_time_to_local (dt);
10199 datetime = gst_date_time_new_from_g_date_time (dt_local);
10201 g_date_time_unref (base_dt);
10202 g_date_time_unref (dt);
10206 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
10207 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
10209 gst_date_time_unref (datetime);
10212 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
10213 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
10215 /* check for fragmented file and get some (default) data */
10216 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
10219 GstByteReader mehd_data;
10221 /* let track parsing or anyone know weird stuff might happen ... */
10222 qtdemux->fragmented = TRUE;
10224 /* compensate for total duration */
10225 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
10227 qtdemux_parse_mehd (qtdemux, &mehd_data);
10230 /* parse all traks */
10231 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
10233 qtdemux_parse_trak (qtdemux, trak);
10234 /* iterate all siblings */
10235 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
10238 /* set duration in the segment info */
10239 gst_qtdemux_get_duration (qtdemux, &duration);
10241 qtdemux->segment.duration = duration;
10242 /* also do not exceed duration; stop is set that way post seek anyway,
10243 * and segment activation falls back to duration,
10244 * whereas loop only checks stop, so let's align this here as well */
10245 qtdemux->segment.stop = duration;
10249 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
10251 qtdemux_parse_udta (qtdemux, udta);
10253 GST_LOG_OBJECT (qtdemux, "No udta node found.");
10256 /* maybe also some tags in meta box */
10257 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
10259 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
10260 qtdemux_parse_udta (qtdemux, udta);
10262 GST_LOG_OBJECT (qtdemux, "No meta node found.");
10265 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
10270 /* taken from ffmpeg */
10272 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
10284 len = (len << 7) | (c & 0x7f);
10292 /* this can change the codec originally present in @list */
10294 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
10295 GNode * esds, GstTagList * list)
10297 int len = QT_UINT32 (esds->data);
10298 guint8 *ptr = esds->data;
10299 guint8 *end = ptr + len;
10301 guint8 *data_ptr = NULL;
10303 guint8 object_type_id = 0;
10304 const char *codec_name = NULL;
10305 GstCaps *caps = NULL;
10307 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
10309 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
10311 while (ptr + 1 < end) {
10312 tag = QT_UINT8 (ptr);
10313 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
10315 len = read_descr_size (ptr, end, &ptr);
10316 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
10318 /* Check the stated amount of data is available for reading */
10319 if (len < 0 || ptr + len > end)
10323 case ES_DESCRIPTOR_TAG:
10324 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
10325 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
10328 case DECODER_CONFIG_DESC_TAG:{
10329 guint max_bitrate, avg_bitrate;
10331 object_type_id = QT_UINT8 (ptr);
10332 max_bitrate = QT_UINT32 (ptr + 5);
10333 avg_bitrate = QT_UINT32 (ptr + 9);
10334 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
10335 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
10336 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
10337 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
10338 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
10339 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
10340 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
10341 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
10343 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
10344 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
10345 avg_bitrate, NULL);
10350 case DECODER_SPECIFIC_INFO_TAG:
10351 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
10352 if (object_type_id == 0xe0 && len == 0x40) {
10358 GST_DEBUG_OBJECT (qtdemux,
10359 "Have VOBSUB palette. Creating palette event");
10360 /* move to decConfigDescr data and read palette */
10362 for (i = 0; i < 16; i++) {
10363 clut[i] = QT_UINT32 (data);
10367 s = gst_structure_new ("application/x-gst-dvd", "event",
10368 G_TYPE_STRING, "dvd-spu-clut-change",
10369 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
10370 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
10371 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
10372 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
10373 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
10374 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
10375 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
10376 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
10379 /* store event and trigger custom processing */
10380 stream->pending_event =
10381 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
10383 /* Generic codec_data handler puts it on the caps */
10390 case SL_CONFIG_DESC_TAG:
10391 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
10395 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
10397 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
10403 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
10404 * in use, and should also be used to override some other parameters for some
10406 switch (object_type_id) {
10407 case 0x20: /* MPEG-4 */
10408 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
10409 * profile_and_level_indication */
10410 if (data_ptr != NULL && data_len >= 5 &&
10411 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
10412 gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
10413 data_ptr + 4, data_len - 4);
10415 break; /* Nothing special needed here */
10416 case 0x21: /* H.264 */
10417 codec_name = "H.264 / AVC";
10418 caps = gst_caps_new_simple ("video/x-h264",
10419 "stream-format", G_TYPE_STRING, "avc",
10420 "alignment", G_TYPE_STRING, "au", NULL);
10422 case 0x40: /* AAC (any) */
10423 case 0x66: /* AAC Main */
10424 case 0x67: /* AAC LC */
10425 case 0x68: /* AAC SSR */
10426 /* Override channels and rate based on the codec_data, as it's often
10428 /* Only do so for basic setup without HE-AAC extension */
10429 if (data_ptr && data_len == 2) {
10430 guint channels, rateindex, rate;
10432 /* FIXME: add gst_codec_utils_aac_get_{channels|sample_rate}()? */
10433 channels = (data_ptr[1] & 0x7f) >> 3;
10434 if (channels > 0 && channels < 7) {
10435 stream->n_channels = channels;
10436 } else if (channels == 7) {
10437 stream->n_channels = 8;
10440 rateindex = ((data_ptr[0] & 0x7) << 1) | ((data_ptr[1] & 0x80) >> 7);
10441 rate = gst_codec_utils_aac_get_sample_rate_from_index (rateindex);
10443 stream->rate = rate;
10446 /* Set level and profile if possible */
10447 if (data_ptr != NULL && data_len >= 2) {
10448 gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
10449 data_ptr, data_len);
10452 case 0x60: /* MPEG-2, various profiles */
10458 codec_name = "MPEG-2 video";
10459 caps = gst_caps_new_simple ("video/mpeg",
10460 "mpegversion", G_TYPE_INT, 2,
10461 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
10463 case 0x69: /* MPEG-2 BC audio */
10464 case 0x6B: /* MPEG-1 audio */
10465 caps = gst_caps_new_simple ("audio/mpeg",
10466 "mpegversion", G_TYPE_INT, 1, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
10467 codec_name = "MPEG-1 audio";
10469 case 0x6A: /* MPEG-1 */
10470 codec_name = "MPEG-1 video";
10471 caps = gst_caps_new_simple ("video/mpeg",
10472 "mpegversion", G_TYPE_INT, 1,
10473 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
10475 case 0x6C: /* MJPEG */
10476 caps = gst_caps_new_empty_simple ("image/jpeg");
10477 codec_name = "Motion-JPEG";
10479 case 0x6D: /* PNG */
10480 caps = gst_caps_new_empty_simple ("image/png");
10481 codec_name = "PNG still images";
10483 case 0x6E: /* JPEG2000 */
10484 codec_name = "JPEG-2000";
10485 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
10487 case 0xA4: /* Dirac */
10488 codec_name = "Dirac";
10489 caps = gst_caps_new_empty_simple ("video/x-dirac");
10491 case 0xA5: /* AC3 */
10492 codec_name = "AC-3 audio";
10493 caps = gst_caps_new_simple ("audio/x-ac3",
10494 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
10496 case 0xA9: /* AC3 */
10497 codec_name = "DTS audio";
10498 caps = gst_caps_new_simple ("audio/x-dts",
10499 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
10501 case 0xE1: /* QCELP */
10502 /* QCELP, the codec_data is a riff tag (little endian) with
10503 * 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). */
10504 caps = gst_caps_new_empty_simple ("audio/qcelp");
10505 codec_name = "QCELP";
10511 /* If we have a replacement caps, then change our caps for this stream */
10513 gst_caps_unref (stream->caps);
10514 stream->caps = caps;
10517 if (codec_name && list)
10518 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
10519 GST_TAG_AUDIO_CODEC, codec_name, NULL);
10521 /* Add the codec_data attribute to caps, if we have it */
10525 buffer = gst_buffer_new_and_alloc (data_len);
10526 gst_buffer_fill (buffer, 0, data_ptr, data_len);
10528 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
10529 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
10531 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
10533 gst_buffer_unref (buffer);
10538 #define _codec(name) \
10540 if (codec_name) { \
10541 *codec_name = g_strdup (name); \
10546 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
10547 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
10549 GstCaps *caps = NULL;
10550 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
10553 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
10554 _codec ("PNG still images");
10555 caps = gst_caps_new_empty_simple ("image/png");
10557 case GST_MAKE_FOURCC ('j', 'p', 'e', 'g'):
10558 _codec ("JPEG still images");
10559 caps = gst_caps_new_empty_simple ("image/jpeg");
10561 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
10562 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
10563 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
10564 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
10565 _codec ("Motion-JPEG");
10566 caps = gst_caps_new_empty_simple ("image/jpeg");
10568 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
10569 _codec ("Motion-JPEG format B");
10570 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
10572 case GST_MAKE_FOURCC ('m', 'j', 'p', '2'):
10573 _codec ("JPEG-2000");
10574 /* override to what it should be according to spec, avoid palette_data */
10575 stream->bits_per_sample = 24;
10576 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
10578 case GST_MAKE_FOURCC ('S', 'V', 'Q', '3'):
10579 _codec ("Sorensen video v.3");
10580 caps = gst_caps_new_simple ("video/x-svq",
10581 "svqversion", G_TYPE_INT, 3, NULL);
10583 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
10584 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
10585 _codec ("Sorensen video v.1");
10586 caps = gst_caps_new_simple ("video/x-svq",
10587 "svqversion", G_TYPE_INT, 1, NULL);
10589 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
10590 caps = gst_caps_new_empty_simple ("video/x-raw");
10591 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
10592 _codec ("Windows Raw RGB");
10594 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
10598 bps = QT_UINT16 (stsd_data + 98);
10601 format = GST_VIDEO_FORMAT_RGB15;
10604 format = GST_VIDEO_FORMAT_RGB16;
10607 format = GST_VIDEO_FORMAT_RGB;
10610 format = GST_VIDEO_FORMAT_ARGB;
10618 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
10619 format = GST_VIDEO_FORMAT_I420;
10621 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
10622 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
10623 format = GST_VIDEO_FORMAT_I420;
10625 case GST_MAKE_FOURCC ('2', 'v', 'u', 'y'):
10626 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
10627 case GST_MAKE_FOURCC ('v', '2', '1', '0'):
10628 format = GST_VIDEO_FORMAT_UYVY;
10630 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
10631 format = GST_VIDEO_FORMAT_r210;
10633 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
10634 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
10635 _codec ("MPEG-1 video");
10636 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
10637 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
10639 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
10640 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
10641 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
10642 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
10643 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
10644 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
10645 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
10646 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
10647 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
10648 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
10649 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
10650 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
10651 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
10652 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
10653 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
10654 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
10655 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
10656 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
10657 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
10658 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
10659 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
10660 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
10661 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
10662 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
10663 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
10664 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
10665 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
10666 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
10667 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
10668 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
10669 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
10670 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
10671 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
10672 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
10673 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
10674 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
10675 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
10676 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
10677 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
10678 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
10679 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
10680 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
10681 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
10682 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
10683 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
10684 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
10685 _codec ("MPEG-2 video");
10686 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
10687 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
10689 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
10690 _codec ("GIF still images");
10691 caps = gst_caps_new_empty_simple ("image/gif");
10693 case GST_MAKE_FOURCC ('h', '2', '6', '3'):
10694 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
10695 case GST_MAKE_FOURCC ('s', '2', '6', '3'):
10696 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
10698 /* ffmpeg uses the height/width props, don't know why */
10699 caps = gst_caps_new_simple ("video/x-h263",
10700 "variant", G_TYPE_STRING, "itu", NULL);
10702 case GST_MAKE_FOURCC ('m', 'p', '4', 'v'):
10703 case GST_MAKE_FOURCC ('M', 'P', '4', 'V'):
10704 _codec ("MPEG-4 video");
10705 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
10706 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
10708 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
10709 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
10710 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
10711 caps = gst_caps_new_simple ("video/x-msmpeg",
10712 "msmpegversion", G_TYPE_INT, 43, NULL);
10714 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
10716 caps = gst_caps_new_simple ("video/x-divx",
10717 "divxversion", G_TYPE_INT, 3, NULL);
10719 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
10720 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
10722 caps = gst_caps_new_simple ("video/x-divx",
10723 "divxversion", G_TYPE_INT, 4, NULL);
10725 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
10727 caps = gst_caps_new_simple ("video/x-divx",
10728 "divxversion", G_TYPE_INT, 5, NULL);
10731 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
10732 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
10733 case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
10734 case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
10735 case GST_MAKE_FOURCC ('F', 'M', 'P', '4'):
10736 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
10737 caps = gst_caps_new_simple ("video/mpeg",
10738 "mpegversion", G_TYPE_INT, 4, NULL);
10740 *codec_name = g_strdup ("MPEG-4");
10743 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
10744 _codec ("Cinepak");
10745 caps = gst_caps_new_empty_simple ("video/x-cinepak");
10747 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
10748 _codec ("Apple QuickDraw");
10749 caps = gst_caps_new_empty_simple ("video/x-qdrw");
10751 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
10752 _codec ("Apple video");
10753 caps = gst_caps_new_empty_simple ("video/x-apple-video");
10755 case GST_MAKE_FOURCC ('H', '2', '6', '4'):
10756 case GST_MAKE_FOURCC ('a', 'v', 'c', '1'):
10757 _codec ("H.264 / AVC");
10758 caps = gst_caps_new_simple ("video/x-h264",
10759 "stream-format", G_TYPE_STRING, "avc",
10760 "alignment", G_TYPE_STRING, "au", NULL);
10762 case GST_MAKE_FOURCC ('a', 'v', 'c', '3'):
10763 _codec ("H.264 / AVC");
10764 caps = gst_caps_new_simple ("video/x-h264",
10765 "stream-format", G_TYPE_STRING, "avc3",
10766 "alignment", G_TYPE_STRING, "au", NULL);
10768 case GST_MAKE_FOURCC ('H', '2', '6', '5'):
10769 case GST_MAKE_FOURCC ('h', 'v', 'c', '1'):
10770 _codec ("H.265 / HEVC");
10771 caps = gst_caps_new_simple ("video/x-h265",
10772 "stream-format", G_TYPE_STRING, "hvc1",
10773 "alignment", G_TYPE_STRING, "au", NULL);
10775 case GST_MAKE_FOURCC ('h', 'e', 'v', '1'):
10776 _codec ("H.265 / HEVC");
10777 caps = gst_caps_new_simple ("video/x-h265",
10778 "stream-format", G_TYPE_STRING, "hev1",
10779 "alignment", G_TYPE_STRING, "au", NULL);
10781 case GST_MAKE_FOURCC ('r', 'l', 'e', ' '):
10782 _codec ("Run-length encoding");
10783 caps = gst_caps_new_simple ("video/x-rle",
10784 "layout", G_TYPE_STRING, "quicktime", NULL);
10786 case GST_MAKE_FOURCC ('W', 'R', 'L', 'E'):
10787 _codec ("Run-length encoding");
10788 caps = gst_caps_new_simple ("video/x-rle",
10789 "layout", G_TYPE_STRING, "microsoft", NULL);
10791 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
10792 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
10793 _codec ("Indeo Video 3");
10794 caps = gst_caps_new_simple ("video/x-indeo",
10795 "indeoversion", G_TYPE_INT, 3, NULL);
10797 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
10798 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
10799 _codec ("Intel Video 4");
10800 caps = gst_caps_new_simple ("video/x-indeo",
10801 "indeoversion", G_TYPE_INT, 4, NULL);
10803 case GST_MAKE_FOURCC ('d', 'v', 'c', 'p'):
10804 case GST_MAKE_FOURCC ('d', 'v', 'c', ' '):
10805 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
10806 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
10807 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
10808 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
10809 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
10810 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
10811 _codec ("DV Video");
10812 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
10813 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
10815 case GST_MAKE_FOURCC ('d', 'v', '5', 'n'): /* DVCPRO50 NTSC */
10816 case GST_MAKE_FOURCC ('d', 'v', '5', 'p'): /* DVCPRO50 PAL */
10817 _codec ("DVCPro50 Video");
10818 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
10819 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
10821 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
10822 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
10823 _codec ("DVCProHD Video");
10824 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
10825 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
10827 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
10828 _codec ("Apple Graphics (SMC)");
10829 caps = gst_caps_new_empty_simple ("video/x-smc");
10831 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
10833 caps = gst_caps_new_empty_simple ("video/x-vp3");
10835 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
10836 _codec ("VP6 Flash");
10837 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
10839 case GST_MAKE_FOURCC ('X', 'i', 'T', 'h'):
10841 caps = gst_caps_new_empty_simple ("video/x-theora");
10842 /* theora uses one byte of padding in the data stream because it does not
10843 * allow 0 sized packets while theora does */
10844 stream->padding = 1;
10846 case GST_MAKE_FOURCC ('d', 'r', 'a', 'c'):
10848 caps = gst_caps_new_empty_simple ("video/x-dirac");
10850 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
10851 _codec ("TIFF still images");
10852 caps = gst_caps_new_empty_simple ("image/tiff");
10854 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
10855 _codec ("Apple Intermediate Codec");
10856 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
10858 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
10859 _codec ("AVID DNxHD");
10860 caps = gst_caps_from_string ("video/x-dnxhd");
10862 case GST_MAKE_FOURCC ('V', 'P', '8', '0'):
10863 _codec ("On2 VP8");
10864 caps = gst_caps_from_string ("video/x-vp8");
10866 case GST_MAKE_FOURCC ('a', 'p', 'c', 's'):
10867 _codec ("Apple ProRes LT");
10869 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
10872 case GST_MAKE_FOURCC ('a', 'p', 'c', 'h'):
10873 _codec ("Apple ProRes HQ");
10875 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
10878 case GST_MAKE_FOURCC ('a', 'p', 'c', 'n'):
10879 _codec ("Apple ProRes");
10881 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
10884 case GST_MAKE_FOURCC ('a', 'p', 'c', 'o'):
10885 _codec ("Apple ProRes Proxy");
10887 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
10890 case GST_MAKE_FOURCC ('a', 'p', '4', 'h'):
10891 _codec ("Apple ProRes 4444");
10893 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
10898 caps = gst_caps_new_simple ("video/x-wmv",
10899 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
10901 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
10904 char *s, fourstr[5];
10906 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
10907 s = g_strdup_printf ("video/x-gst-fourcc-%s", g_strstrip (fourstr));
10908 caps = gst_caps_new_empty_simple (s);
10913 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
10916 gst_video_info_init (&info);
10917 gst_video_info_set_format (&info, format, stream->width, stream->height);
10918 caps = gst_video_info_to_caps (&info);
10919 *codec_name = gst_pb_utils_get_codec_description (caps);
10921 /* enable clipping for raw video streams */
10922 stream->need_clip = TRUE;
10929 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
10930 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
10933 const GstStructure *s;
10937 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
10940 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
10941 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
10942 _codec ("Raw 8-bit PCM audio");
10943 caps = gst_caps_new_simple ("audio/x-raw",
10944 "format", G_TYPE_STRING, "U8",
10945 "layout", G_TYPE_STRING, "interleaved", NULL);
10947 case GST_MAKE_FOURCC ('t', 'w', 'o', 's'):
10948 endian = G_BIG_ENDIAN;
10950 case GST_MAKE_FOURCC ('s', 'o', 'w', 't'):
10954 GstAudioFormat format;
10957 endian = G_LITTLE_ENDIAN;
10959 depth = stream->bytes_per_packet * 8;
10960 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
10962 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
10966 caps = gst_caps_new_simple ("audio/x-raw",
10967 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
10968 "layout", G_TYPE_STRING, "interleaved", NULL);
10971 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
10972 _codec ("Raw 64-bit floating-point audio");
10973 caps = gst_caps_new_simple ("audio/x-raw",
10974 "format", G_TYPE_STRING, "F64BE",
10975 "layout", G_TYPE_STRING, "interleaved", NULL);
10977 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
10978 _codec ("Raw 32-bit floating-point audio");
10979 caps = gst_caps_new_simple ("audio/x-raw",
10980 "format", G_TYPE_STRING, "F32BE",
10981 "layout", G_TYPE_STRING, "interleaved", NULL);
10984 _codec ("Raw 24-bit PCM audio");
10985 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
10987 caps = gst_caps_new_simple ("audio/x-raw",
10988 "format", G_TYPE_STRING, "S24BE",
10989 "layout", G_TYPE_STRING, "interleaved", NULL);
10991 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
10992 _codec ("Raw 32-bit PCM audio");
10993 caps = gst_caps_new_simple ("audio/x-raw",
10994 "format", G_TYPE_STRING, "S32BE",
10995 "layout", G_TYPE_STRING, "interleaved", NULL);
10997 case GST_MAKE_FOURCC ('u', 'l', 'a', 'w'):
10998 _codec ("Mu-law audio");
10999 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
11001 case GST_MAKE_FOURCC ('a', 'l', 'a', 'w'):
11002 _codec ("A-law audio");
11003 caps = gst_caps_new_empty_simple ("audio/x-alaw");
11007 _codec ("Microsoft ADPCM");
11008 /* Microsoft ADPCM-ACM code 2 */
11009 caps = gst_caps_new_simple ("audio/x-adpcm",
11010 "layout", G_TYPE_STRING, "microsoft", NULL);
11014 _codec ("DVI/IMA ADPCM");
11015 caps = gst_caps_new_simple ("audio/x-adpcm",
11016 "layout", G_TYPE_STRING, "dvi", NULL);
11020 _codec ("DVI/Intel IMA ADPCM");
11021 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
11022 caps = gst_caps_new_simple ("audio/x-adpcm",
11023 "layout", G_TYPE_STRING, "quicktime", NULL);
11027 /* MPEG layer 3, CBR only (pre QT4.1) */
11028 case GST_MAKE_FOURCC ('.', 'm', 'p', '3'):
11029 _codec ("MPEG-1 layer 3");
11030 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
11031 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
11032 "mpegversion", G_TYPE_INT, 1, NULL);
11035 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
11036 _codec ("EAC-3 audio");
11037 caps = gst_caps_new_simple ("audio/x-eac3",
11038 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
11039 stream->sampled = TRUE;
11041 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
11042 case GST_MAKE_FOURCC ('a', 'c', '-', '3'):
11043 _codec ("AC-3 audio");
11044 caps = gst_caps_new_simple ("audio/x-ac3",
11045 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
11046 stream->sampled = TRUE;
11048 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
11049 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
11050 _codec ("DTS audio");
11051 caps = gst_caps_new_simple ("audio/x-dts",
11052 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
11053 stream->sampled = TRUE;
11055 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
11056 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
11057 _codec ("DTS-HD audio");
11058 caps = gst_caps_new_simple ("audio/x-dts",
11059 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
11060 stream->sampled = TRUE;
11062 case GST_MAKE_FOURCC ('M', 'A', 'C', '3'):
11064 caps = gst_caps_new_simple ("audio/x-mace",
11065 "maceversion", G_TYPE_INT, 3, NULL);
11067 case GST_MAKE_FOURCC ('M', 'A', 'C', '6'):
11069 caps = gst_caps_new_simple ("audio/x-mace",
11070 "maceversion", G_TYPE_INT, 6, NULL);
11072 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
11074 caps = gst_caps_new_empty_simple ("application/ogg");
11076 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
11077 _codec ("DV audio");
11078 caps = gst_caps_new_empty_simple ("audio/x-dv");
11080 case GST_MAKE_FOURCC ('m', 'p', '4', 'a'):
11081 _codec ("MPEG-4 AAC audio");
11082 caps = gst_caps_new_simple ("audio/mpeg",
11083 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
11084 "stream-format", G_TYPE_STRING, "raw", NULL);
11086 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
11087 _codec ("QDesign Music");
11088 caps = gst_caps_new_empty_simple ("audio/x-qdm");
11090 case GST_MAKE_FOURCC ('Q', 'D', 'M', '2'):
11091 _codec ("QDesign Music v.2");
11092 /* FIXME: QDesign music version 2 (no constant) */
11093 if (FALSE && data) {
11094 caps = gst_caps_new_simple ("audio/x-qdm2",
11095 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
11096 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
11097 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
11099 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
11102 case GST_MAKE_FOURCC ('a', 'g', 's', 'm'):
11103 _codec ("GSM audio");
11104 caps = gst_caps_new_empty_simple ("audio/x-gsm");
11106 case GST_MAKE_FOURCC ('s', 'a', 'm', 'r'):
11107 _codec ("AMR audio");
11108 caps = gst_caps_new_empty_simple ("audio/AMR");
11110 case GST_MAKE_FOURCC ('s', 'a', 'w', 'b'):
11111 _codec ("AMR-WB audio");
11112 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
11114 case GST_MAKE_FOURCC ('i', 'm', 'a', '4'):
11115 _codec ("Quicktime IMA ADPCM");
11116 caps = gst_caps_new_simple ("audio/x-adpcm",
11117 "layout", G_TYPE_STRING, "quicktime", NULL);
11119 case GST_MAKE_FOURCC ('a', 'l', 'a', 'c'):
11120 _codec ("Apple lossless audio");
11121 caps = gst_caps_new_empty_simple ("audio/x-alac");
11123 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
11124 _codec ("QualComm PureVoice");
11125 caps = gst_caps_from_string ("audio/qcelp");
11129 caps = gst_caps_new_empty_simple ("audio/x-wma");
11131 case GST_MAKE_FOURCC ('l', 'p', 'c', 'm'):
11136 GstAudioFormat format;
11139 FLAG_IS_FLOAT = 0x1,
11140 FLAG_IS_BIG_ENDIAN = 0x2,
11141 FLAG_IS_SIGNED = 0x4,
11142 FLAG_IS_PACKED = 0x8,
11143 FLAG_IS_ALIGNED_HIGH = 0x10,
11144 FLAG_IS_NON_INTERLEAVED = 0x20
11146 _codec ("Raw LPCM audio");
11148 if (data && len >= 56) {
11149 depth = QT_UINT32 (data + 40);
11150 flags = QT_UINT32 (data + 44);
11151 width = QT_UINT32 (data + 48) * 8 / stream->n_channels;
11153 if ((flags & FLAG_IS_FLOAT) == 0) {
11158 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
11159 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
11160 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
11161 caps = gst_caps_new_simple ("audio/x-raw",
11162 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
11163 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
11164 "non-interleaved" : "interleaved", NULL);
11171 if (flags & FLAG_IS_BIG_ENDIAN)
11172 format = GST_AUDIO_FORMAT_F64BE;
11174 format = GST_AUDIO_FORMAT_F64LE;
11176 if (flags & FLAG_IS_BIG_ENDIAN)
11177 format = GST_AUDIO_FORMAT_F32BE;
11179 format = GST_AUDIO_FORMAT_F32LE;
11181 caps = gst_caps_new_simple ("audio/x-raw",
11182 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
11183 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
11184 "non-interleaved" : "interleaved", NULL);
11188 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
11192 char *s, fourstr[5];
11194 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11195 s = g_strdup_printf ("audio/x-gst-fourcc-%s", g_strstrip (fourstr));
11196 caps = gst_caps_new_empty_simple (s);
11202 GstCaps *templ_caps =
11203 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
11204 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
11205 gst_caps_unref (caps);
11206 gst_caps_unref (templ_caps);
11207 caps = intersection;
11210 /* enable clipping for raw audio streams */
11211 s = gst_caps_get_structure (caps, 0);
11212 name = gst_structure_get_name (s);
11213 if (g_str_has_prefix (name, "audio/x-raw")) {
11214 stream->need_clip = TRUE;
11215 stream->max_buffer_size = 4096 * stream->bytes_per_frame;
11216 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
11222 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
11223 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
11227 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
11230 case GST_MAKE_FOURCC ('m', 'p', '4', 's'):
11231 _codec ("DVD subtitle");
11232 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
11233 stream->need_process = TRUE;
11235 case GST_MAKE_FOURCC ('t', 'e', 'x', 't'):
11236 _codec ("Quicktime timed text");
11238 case GST_MAKE_FOURCC ('t', 'x', '3', 'g'):
11239 _codec ("3GPP timed text");
11241 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
11243 /* actual text piece needs to be extracted */
11244 stream->need_process = TRUE;
11248 char *s, fourstr[5];
11250 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11251 s = g_strdup_printf ("text/x-gst-fourcc-%s", g_strstrip (fourstr));
11252 caps = gst_caps_new_empty_simple (s);
11260 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
11261 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
11266 case GST_MAKE_FOURCC ('m', '1', 'v', ' '):
11267 _codec ("MPEG 1 video");
11268 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
11269 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);