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 Corporation
10 * Copyright (C) <2014> Centricular Ltd
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Library General Public
14 * License as published by the Free Software Foundation; either
15 * version 2 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Library General Public License for more details.
22 * You should have received a copy of the GNU Library General Public
23 * License along with this library; if not, write to the
24 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
25 * Boston, MA 02110-1301, USA.
29 * SECTION:element-qtdemux
31 * Demuxes a .mov file into raw or compressed audio and/or video streams.
33 * This element supports both push and pull-based scheduling, depending on the
34 * capabilities of the upstream elements.
37 * <title>Example launch line</title>
39 * gst-launch-1.0 filesrc location=test.mov ! qtdemux name=demux demux.audio_0 ! queue ! decodebin ! audioconvert ! audioresample ! autoaudiosink demux.video_0 ! queue ! decodebin ! videoconvert ! videoscale ! autovideosink
40 * ]| Play (parse and decode) a .mov file and try to output it to
41 * an automatically detected soundcard and videosink. If the MOV file contains
42 * compressed audio or video data, this will only work if you have the
43 * right decoder elements/plugins installed.
51 #include "gst/gst-i18n-plugin.h"
53 #include <glib/gprintf.h>
54 #include <gst/tag/tag.h>
55 #include <gst/audio/audio.h>
56 #include <gst/video/video.h>
58 #include "qtatomparser.h"
59 #include "qtdemux_types.h"
60 #include "qtdemux_dump.h"
62 #include "descriptors.h"
63 #include "qtdemux_lang.h"
65 #include "qtpalette.h"
67 #include "gst/riff/riff-media.h"
68 #include "gst/riff/riff-read.h"
70 #include <gst/pbutils/pbutils.h>
77 #include <gst/math-compat.h>
83 /* max. size considered 'sane' for non-mdat atoms */
84 #define QTDEMUX_MAX_ATOM_SIZE (25*1024*1024)
86 /* if the sample index is larger than this, something is likely wrong */
87 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (50*1024*1024)
89 /* For converting qt creation times to unix epoch times */
90 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
91 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
92 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
93 QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
95 #define STREAM_IS_EOS(s) (s->time_position == GST_CLOCK_TIME_NONE)
97 GST_DEBUG_CATEGORY (qtdemux_debug);
99 /*typedef struct _QtNode QtNode; */
100 typedef struct _QtDemuxSegment QtDemuxSegment;
101 typedef struct _QtDemuxSample QtDemuxSample;
110 struct _QtDemuxSample
113 gint32 pts_offset; /* Add this value to timestamp to get the pts */
115 guint64 timestamp; /* DTS In mov time */
116 guint32 duration; /* In mov time */
117 gboolean keyframe; /* TRUE when this packet is a keyframe */
120 /* Macros for converting to/from timescale */
121 #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale))
122 #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND))
124 #define QTTIME_TO_GSTTIME(qtdemux, value) (gst_util_uint64_scale((value), GST_SECOND, (qtdemux)->timescale))
125 #define GSTTIME_TO_QTTIME(qtdemux, value) (gst_util_uint64_scale((value), (qtdemux)->timescale, GST_SECOND))
127 /* timestamp is the DTS */
128 #define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp))
129 /* timestamp + offset is the PTS */
130 #define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (stream)->cslg_shift + (sample)->pts_offset))
131 /* timestamp + duration - dts is the duration */
132 #define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts))
134 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
137 * Quicktime has tracks and segments. A track is a continuous piece of
138 * multimedia content. The track is not always played from start to finish but
139 * instead, pieces of the track are 'cut out' and played in sequence. This is
140 * what the segments do.
142 * Inside the track we have keyframes (K) and delta frames. The track has its
143 * own timing, which starts from 0 and extends to end. The position in the track
144 * is called the media_time.
146 * The segments now describe the pieces that should be played from this track
147 * and are basically tuples of media_time/duration/rate entries. We can have
148 * multiple segments and they are all played after one another. An example:
150 * segment 1: media_time: 1 second, duration: 1 second, rate 1
151 * segment 2: media_time: 3 second, duration: 2 second, rate 2
153 * To correctly play back this track, one must play: 1 second of media starting
154 * from media_time 1 followed by 2 seconds of media starting from media_time 3
157 * Each of the segments will be played at a specific time, the first segment at
158 * time 0, the second one after the duration of the first one, etc.. Note that
159 * the time in resulting playback is not identical to the media_time of the
162 * Visually, assuming the track has 4 second of media_time:
165 * .-----------------------------------------------------------.
166 * track: | K.....K.........K........K.......K.......K...........K... |
167 * '-----------------------------------------------------------'
169 * .------------^ ^ .----------^ ^
170 * / .-------------' / .------------------'
172 * .--------------. .--------------.
173 * | segment 1 | | segment 2 |
174 * '--------------' '--------------'
176 * The challenge here is to cut out the right pieces of the track for each of
177 * the playback segments. This fortunately can easily be done with the SEGMENT
178 * events of GStreamer.
180 * For playback of segment 1, we need to provide the decoder with the keyframe
181 * (a), in the above figure, but we must instruct it only to output the decoded
182 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
183 * position set to the time of the segment: 0.
185 * We then proceed to push data from keyframe (a) to frame (b). The decoder
186 * decodes but clips all before media_time 1.
188 * After finishing a segment, we push out a new SEGMENT event with the clipping
189 * boundaries of the new data.
191 * This is a good usecase for the GStreamer accumulated SEGMENT events.
194 struct _QtDemuxSegment
196 /* global time and duration, all gst time */
198 GstClockTime stop_time;
199 GstClockTime duration;
200 /* media time of trak, all gst time */
201 GstClockTime media_start;
202 GstClockTime media_stop;
204 /* Media start time in trak timescale units */
205 guint32 trak_media_start;
208 #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
210 /* Used with fragmented MP4 files (mfra atom) */
215 } QtDemuxRandomAccessEntry;
217 struct _QtDemuxStream
228 gboolean new_stream; /* signals that a stream_start is required */
229 gboolean on_keyframe; /* if this stream last pushed buffer was a
230 * keyframe. This is important to identify
231 * where to stop pushing buffers after a
232 * segment stop time */
234 /* if the stream has a redirect URI in its headers, we store it here */
241 guint64 duration; /* in timescale */
245 gchar lang_id[4]; /* ISO 639-2T language code */
249 QtDemuxSample *samples;
250 gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */
251 guint32 first_duration; /* duration in timescale of first sample, used for figuring out
252 the framerate, in timescale units */
253 guint32 offset_in_sample;
254 guint32 max_buffer_size;
256 /* if we use chunks or samples */
268 /* Numerator/denominator framerate */
271 guint16 bits_per_sample;
272 guint16 color_table_id;
273 GstMemory *rgb8_palette;
278 guint samples_per_packet;
279 guint samples_per_frame;
280 guint bytes_per_packet;
281 guint bytes_per_sample;
282 guint bytes_per_frame;
286 gboolean use_allocator;
287 GstAllocator *allocator;
288 GstAllocationParams params;
290 /* when a discontinuity is pending */
293 /* list of buffers to push first */
296 /* if we need to clip this buffer. This is only needed for uncompressed
300 /* buffer needs some custom processing, e.g. subtitles */
301 gboolean need_process;
303 /* current position */
304 guint32 segment_index;
305 guint32 sample_index;
306 GstClockTime time_position; /* in gst time */
307 guint64 accumulated_base;
309 /* the Gst segment we are processing out, used for clipping */
311 guint32 segment_seqnum; /* segment event seqnum obtained from seek */
313 /* quicktime segments */
315 QtDemuxSegment *segments;
316 gboolean dummy_segment;
321 GstTagList *pending_tags;
322 gboolean send_global_tags;
324 GstEvent *pending_event;
334 gboolean chunks_are_samples; /* TRUE means treat chunks as samples */
338 GstByteReader co_chunk;
340 guint32 current_chunk;
342 guint32 samples_per_chunk;
343 guint32 stco_sample_index;
345 guint32 sample_size; /* 0 means variable sizes are stored in stsz */
348 guint32 n_samples_per_chunk;
349 guint32 stsc_chunk_index;
350 guint32 stsc_sample_index;
351 guint64 chunk_offset;
354 guint32 stts_samples;
355 guint32 n_sample_times;
356 guint32 stts_sample_index;
358 guint32 stts_duration;
360 gboolean stss_present;
361 guint32 n_sample_syncs;
364 gboolean stps_present;
365 guint32 n_sample_partial_syncs;
367 QtDemuxRandomAccessEntry *ra_entries;
370 const QtDemuxRandomAccessEntry *pending_seek;
373 gboolean ctts_present;
374 guint32 n_composition_times;
376 guint32 ctts_sample_index;
384 gboolean parsed_trex;
385 guint32 def_sample_duration;
386 guint32 def_sample_size;
387 guint32 def_sample_flags;
391 /* stereoscopic video streams */
392 GstVideoMultiviewMode multiview_mode;
393 GstVideoMultiviewFlags multiview_flags;
398 QTDEMUX_STATE_INITIAL, /* Initial state (haven't got the header yet) */
399 QTDEMUX_STATE_HEADER, /* Parsing the header */
400 QTDEMUX_STATE_MOVIE, /* Parsing/Playing the media data */
401 QTDEMUX_STATE_BUFFER_MDAT /* Buffering the mdat atom */
404 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
405 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
406 guint32 fourcc, GstByteReader * parser);
407 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
408 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
409 guint32 fourcc, GstByteReader * parser);
411 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
413 static GstStaticPadTemplate gst_qtdemux_sink_template =
414 GST_STATIC_PAD_TEMPLATE ("sink",
417 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
421 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
422 GST_STATIC_PAD_TEMPLATE ("video_%u",
425 GST_STATIC_CAPS_ANY);
427 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
428 GST_STATIC_PAD_TEMPLATE ("audio_%u",
431 GST_STATIC_CAPS_ANY);
433 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
434 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
437 GST_STATIC_CAPS_ANY);
439 #define gst_qtdemux_parent_class parent_class
440 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
442 static void gst_qtdemux_dispose (GObject * object);
445 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
446 GstClockTime media_time);
448 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
449 QtDemuxStream * str, gint64 media_offset);
452 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
453 static GstIndex *gst_qtdemux_get_index (GstElement * element);
455 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
456 GstStateChange transition);
457 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
458 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
459 GstObject * parent, GstPadMode mode, gboolean active);
461 static void gst_qtdemux_loop (GstPad * pad);
462 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
464 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
466 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
467 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
468 QtDemuxStream * stream);
469 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
472 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
473 const guint8 * buffer, guint length);
474 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
475 const guint8 * buffer, guint length);
476 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
477 static void qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist,
480 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
481 QtDemuxStream * stream, GNode * esds, GstTagList * list);
482 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
483 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
484 gchar ** codec_name);
485 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
486 QtDemuxStream * stream, guint32 fourcc, const guint8 * data, int len,
487 gchar ** codec_name);
488 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux,
489 QtDemuxStream * stream, guint32 fourcc, const guint8 * data,
490 gchar ** codec_name);
491 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
492 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
493 gchar ** codec_name);
495 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
496 QtDemuxStream * stream, guint32 n);
497 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
498 static void gst_qtdemux_stream_free (GstQTDemux * qtdemux,
499 QtDemuxStream * stream);
500 static void gst_qtdemux_stream_clear (GstQTDemux * qtdemux,
501 QtDemuxStream * stream);
502 static void gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int index);
503 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
504 static void qtdemux_do_allocation (GstQTDemux * qtdemux,
505 QtDemuxStream * stream);
507 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
508 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
511 gst_qtdemux_class_init (GstQTDemuxClass * klass)
513 GObjectClass *gobject_class;
514 GstElementClass *gstelement_class;
516 gobject_class = (GObjectClass *) klass;
517 gstelement_class = (GstElementClass *) klass;
519 parent_class = g_type_class_peek_parent (klass);
521 gobject_class->dispose = gst_qtdemux_dispose;
523 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
525 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
526 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
529 gst_tag_register_musicbrainz_tags ();
531 gst_element_class_add_pad_template (gstelement_class,
532 gst_static_pad_template_get (&gst_qtdemux_sink_template));
533 gst_element_class_add_pad_template (gstelement_class,
534 gst_static_pad_template_get (&gst_qtdemux_videosrc_template));
535 gst_element_class_add_pad_template (gstelement_class,
536 gst_static_pad_template_get (&gst_qtdemux_audiosrc_template));
537 gst_element_class_add_pad_template (gstelement_class,
538 gst_static_pad_template_get (&gst_qtdemux_subsrc_template));
539 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
541 "Demultiplex a QuickTime file into audio and video streams",
542 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
544 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
549 gst_qtdemux_init (GstQTDemux * qtdemux)
552 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
553 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
554 gst_pad_set_activatemode_function (qtdemux->sinkpad,
555 qtdemux_sink_activate_mode);
556 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
557 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
558 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
560 qtdemux->state = QTDEMUX_STATE_INITIAL;
561 qtdemux->pullbased = FALSE;
562 qtdemux->posted_redirect = FALSE;
563 qtdemux->neededbytes = 16;
565 qtdemux->adapter = gst_adapter_new ();
567 qtdemux->first_mdat = -1;
568 qtdemux->got_moov = FALSE;
569 qtdemux->mdatoffset = -1;
570 qtdemux->mdatbuffer = NULL;
571 qtdemux->restoredata_buffer = NULL;
572 qtdemux->restoredata_offset = -1;
573 qtdemux->fragment_start = -1;
574 qtdemux->fragment_start_offset = -1;
575 qtdemux->media_caps = NULL;
576 qtdemux->exposed = FALSE;
577 qtdemux->mss_mode = FALSE;
578 qtdemux->pending_newsegment = NULL;
579 qtdemux->upstream_newsegment = FALSE;
580 qtdemux->have_group_id = FALSE;
581 qtdemux->group_id = G_MAXUINT;
582 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
583 qtdemux->flowcombiner = gst_flow_combiner_new ();
585 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
589 gst_qtdemux_dispose (GObject * object)
591 GstQTDemux *qtdemux = GST_QTDEMUX (object);
593 if (qtdemux->adapter) {
594 g_object_unref (G_OBJECT (qtdemux->adapter));
595 qtdemux->adapter = NULL;
597 gst_flow_combiner_free (qtdemux->flowcombiner);
599 G_OBJECT_CLASS (parent_class)->dispose (object);
603 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
605 if (qtdemux->posted_redirect) {
606 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
607 (_("This file contains no playable streams.")),
608 ("no known streams found, a redirect message has been posted"));
610 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
611 (_("This file contains no playable streams.")),
612 ("no known streams found"));
617 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
619 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
620 mem, size, 0, size, mem, free_func);
624 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
631 if (G_UNLIKELY (size == 0)) {
633 GstBuffer *tmp = NULL;
635 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
636 if (ret != GST_FLOW_OK)
639 gst_buffer_map (tmp, &map, GST_MAP_READ);
640 size = QT_UINT32 (map.data);
641 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
643 gst_buffer_unmap (tmp, &map);
644 gst_buffer_unref (tmp);
647 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
648 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
649 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
650 /* we're pulling header but already got most interesting bits,
651 * so never mind the rest (e.g. tags) (that much) */
652 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
656 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
657 (_("This file is invalid and cannot be played.")),
658 ("atom has bogus size %" G_GUINT64_FORMAT, size));
659 return GST_FLOW_ERROR;
663 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
665 if (G_UNLIKELY (flow != GST_FLOW_OK))
668 bsize = gst_buffer_get_size (*buf);
669 /* Catch short reads - we don't want any partial atoms */
670 if (G_UNLIKELY (bsize < size)) {
671 GST_WARNING_OBJECT (qtdemux,
672 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
673 gst_buffer_unref (*buf);
683 gst_qtdemux_src_convert (GstPad * pad, GstFormat src_format, gint64 src_value,
684 GstFormat dest_format, gint64 * dest_value)
687 QtDemuxStream *stream = gst_pad_get_element_private (pad);
688 GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
691 if (stream->subtype != FOURCC_vide) {
696 switch (src_format) {
697 case GST_FORMAT_TIME:
698 switch (dest_format) {
699 case GST_FORMAT_BYTES:{
700 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
704 *dest_value = stream->samples[index].offset;
706 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
707 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
708 GST_TIME_ARGS (src_value), *dest_value);
716 case GST_FORMAT_BYTES:
717 switch (dest_format) {
718 case GST_FORMAT_TIME:{
720 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
727 QTSTREAMTIME_TO_GSTTIME (stream,
728 stream->samples[index].timestamp);
729 GST_DEBUG_OBJECT (qtdemux,
730 "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
731 GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
744 gst_object_unref (qtdemux);
751 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
755 *duration = GST_CLOCK_TIME_NONE;
757 if (qtdemux->duration != 0) {
758 if (qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
759 *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
766 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
769 gboolean res = FALSE;
770 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
772 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
774 switch (GST_QUERY_TYPE (query)) {
775 case GST_QUERY_POSITION:{
778 gst_query_parse_position (query, &fmt, NULL);
779 if (fmt == GST_FORMAT_TIME
780 && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
781 gst_query_set_position (query, GST_FORMAT_TIME,
782 qtdemux->segment.position);
787 case GST_QUERY_DURATION:{
790 gst_query_parse_duration (query, &fmt, NULL);
791 if (fmt == GST_FORMAT_TIME) {
792 /* First try to query upstream */
793 res = gst_pad_query_default (pad, parent, query);
796 if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
797 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
804 case GST_QUERY_CONVERT:{
805 GstFormat src_fmt, dest_fmt;
806 gint64 src_value, dest_value = 0;
808 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
810 res = gst_qtdemux_src_convert (pad,
811 src_fmt, src_value, dest_fmt, &dest_value);
813 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
818 case GST_QUERY_FORMATS:
819 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
822 case GST_QUERY_SEEKING:{
826 /* try upstream first */
827 res = gst_pad_query_default (pad, parent, query);
830 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
831 if (fmt == GST_FORMAT_TIME) {
832 GstClockTime duration = GST_CLOCK_TIME_NONE;
834 gst_qtdemux_get_duration (qtdemux, &duration);
836 if (!qtdemux->pullbased) {
839 /* we might be able with help from upstream */
841 q = gst_query_new_seeking (GST_FORMAT_BYTES);
842 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
843 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
844 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
848 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
854 case GST_QUERY_SEGMENT:
859 format = qtdemux->segment.format;
862 gst_segment_to_stream_time (&qtdemux->segment, format,
863 qtdemux->segment.start);
864 if ((stop = qtdemux->segment.stop) == -1)
865 stop = qtdemux->segment.duration;
867 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
869 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
874 res = gst_pad_query_default (pad, parent, query);
882 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
884 if (G_LIKELY (stream->pad)) {
885 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
886 GST_DEBUG_PAD_NAME (stream->pad));
888 if (G_UNLIKELY (stream->pending_tags)) {
889 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
890 stream->pending_tags);
891 gst_pad_push_event (stream->pad,
892 gst_event_new_tag (stream->pending_tags));
893 stream->pending_tags = NULL;
896 if (G_UNLIKELY (stream->send_global_tags && qtdemux->tag_list)) {
897 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
899 gst_pad_push_event (stream->pad,
900 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
901 stream->send_global_tags = FALSE;
906 /* push event on all source pads; takes ownership of the event */
908 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
911 gboolean has_valid_stream = FALSE;
912 GstEventType etype = GST_EVENT_TYPE (event);
914 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
915 GST_EVENT_TYPE_NAME (event));
917 for (n = 0; n < qtdemux->n_streams; n++) {
919 QtDemuxStream *stream = qtdemux->streams[n];
920 GST_DEBUG_OBJECT (qtdemux, "pushing on pad %i", n);
922 if ((pad = stream->pad)) {
923 has_valid_stream = TRUE;
925 if (etype == GST_EVENT_EOS) {
926 /* let's not send twice */
927 if (stream->sent_eos)
929 stream->sent_eos = TRUE;
932 gst_pad_push_event (pad, gst_event_ref (event));
936 gst_event_unref (event);
938 /* if it is EOS and there are no pads, post an error */
939 if (!has_valid_stream && etype == GST_EVENT_EOS) {
940 gst_qtdemux_post_no_playable_stream_error (qtdemux);
944 /* push a pending newsegment event, if any from the streaming thread */
946 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
948 if (qtdemux->pending_newsegment) {
949 gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
950 qtdemux->pending_newsegment = NULL;
960 find_func (QtDemuxSample * s1, guint64 * media_time, gpointer user_data)
962 if (s1->timestamp + s1->pts_offset > *media_time)
968 /* find the index of the sample that includes the data for @media_time using a
969 * binary search. Only to be called in optimized cases of linear search below.
971 * Returns the index of the sample.
974 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
977 QtDemuxSample *result;
980 /* convert media_time to mov format */
982 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
984 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
985 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
986 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
988 if (G_LIKELY (result))
989 index = result - str->samples;
998 /* find the index of the sample that includes the data for @media_offset using a
1001 * Returns the index of the sample.
1004 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
1005 QtDemuxStream * str, gint64 media_offset)
1007 QtDemuxSample *result = str->samples;
1010 if (result == NULL || str->n_samples == 0)
1013 if (media_offset == result->offset)
1017 while (index < str->n_samples - 1) {
1018 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1021 if (media_offset < result->offset)
1032 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1037 /* find the index of the sample that includes the data for @media_time using a
1038 * linear search, and keeping in mind that not all samples may have been parsed
1039 * yet. If possible, it will delegate to binary search.
1041 * Returns the index of the sample.
1044 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
1045 GstClockTime media_time)
1049 QtDemuxSample *sample;
1051 /* convert media_time to mov format */
1053 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1055 sample = str->samples;
1056 if (mov_time == sample->timestamp + sample->pts_offset)
1059 /* use faster search if requested time in already parsed range */
1060 sample = str->samples + str->stbl_index;
1061 if (str->stbl_index >= 0 &&
1062 mov_time <= (sample->timestamp + sample->pts_offset))
1063 return gst_qtdemux_find_index (qtdemux, str, media_time);
1065 while (index < str->n_samples - 1) {
1066 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1069 sample = str->samples + index + 1;
1070 if (mov_time < (sample->timestamp + sample->pts_offset))
1080 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1085 /* find the index of the keyframe needed to decode the sample at @index
1088 * Returns the index of the keyframe.
1091 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1094 guint32 new_index = index;
1096 if (index >= str->n_samples) {
1097 new_index = str->n_samples;
1101 /* all keyframes, return index */
1102 if (str->all_keyframe) {
1107 /* else go back until we have a keyframe */
1109 if (str->samples[new_index].keyframe)
1119 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index before index %u "
1120 "gave %u", index, new_index);
1125 /* find the segment for @time_position for @stream
1127 * Returns the index of the segment containing @time_position.
1128 * Returns the last segment and sets the @eos variable to TRUE
1129 * if the time is beyond the end. @eos may be NULL
1132 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1133 GstClockTime time_position)
1138 GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1139 GST_TIME_ARGS (time_position));
1142 for (i = 0; i < stream->n_segments; i++) {
1143 QtDemuxSegment *segment = &stream->segments[i];
1145 GST_LOG_OBJECT (stream->pad,
1146 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1147 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1149 /* For the last segment we include stop_time in the last segment */
1150 if (i < stream->n_segments - 1) {
1151 if (segment->time <= time_position && time_position < segment->stop_time) {
1152 GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1157 /* Last segment always matches */
1165 /* move the stream @str to the sample position @index.
1167 * Updates @str->sample_index and marks discontinuity if needed.
1170 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1173 /* no change needed */
1174 if (index == str->sample_index)
1177 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1180 /* position changed, we have a discont */
1181 str->sample_index = index;
1182 str->offset_in_sample = 0;
1183 /* Each time we move in the stream we store the position where we are
1185 str->from_sample = index;
1186 str->discont = TRUE;
1190 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1191 gboolean use_sparse, gint64 * key_time, gint64 * key_offset)
1194 gint64 min_byte_offset = -1;
1197 min_offset = desired_time;
1199 /* for each stream, find the index of the sample in the segment
1200 * and move back to the previous keyframe. */
1201 for (n = 0; n < qtdemux->n_streams; n++) {
1203 guint32 index, kindex;
1205 GstClockTime media_start;
1206 GstClockTime media_time;
1207 GstClockTime seg_time;
1208 QtDemuxSegment *seg;
1210 str = qtdemux->streams[n];
1212 if (str->sparse && !use_sparse)
1215 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1216 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1218 /* get segment and time in the segment */
1219 seg = &str->segments[seg_idx];
1220 seg_time = desired_time - seg->time;
1222 /* get the media time in the segment */
1223 media_start = seg->media_start + seg_time;
1225 /* get the index of the sample with media time */
1226 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1227 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1228 " at offset %" G_GUINT64_FORMAT,
1229 GST_TIME_ARGS (media_start), index, str->samples[index].offset);
1231 /* find previous keyframe */
1232 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index);
1234 /* if the keyframe is at a different position, we need to update the
1235 * requested seek time */
1236 if (index != kindex) {
1239 /* get timestamp of keyframe */
1240 media_time = QTSAMPLE_DTS (str, &str->samples[kindex]);
1241 GST_DEBUG_OBJECT (qtdemux,
1242 "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1243 G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1244 str->samples[kindex].offset);
1246 /* keyframes in the segment get a chance to change the
1247 * desired_offset. keyframes out of the segment are
1249 if (media_time >= seg->media_start) {
1250 GstClockTime seg_time;
1252 /* this keyframe is inside the segment, convert back to
1254 seg_time = (media_time - seg->media_start) + seg->time;
1255 if (seg_time < min_offset)
1256 min_offset = seg_time;
1260 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1261 min_byte_offset = str->samples[index].offset;
1265 *key_time = min_offset;
1267 *key_offset = min_byte_offset;
1271 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1272 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1276 g_return_val_if_fail (format != NULL, FALSE);
1277 g_return_val_if_fail (cur != NULL, FALSE);
1278 g_return_val_if_fail (stop != NULL, FALSE);
1280 if (*format == GST_FORMAT_TIME)
1284 if (cur_type != GST_SEEK_TYPE_NONE)
1285 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1286 if (res && stop_type != GST_SEEK_TYPE_NONE)
1287 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1290 *format = GST_FORMAT_TIME;
1295 /* perform seek in push based mode:
1296 find BYTE position to move to based on time and delegate to upstream
1299 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1304 GstSeekType cur_type, stop_type;
1305 gint64 cur, stop, key_cur;
1308 gint64 original_stop;
1311 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1313 gst_event_parse_seek (event, &rate, &format, &flags,
1314 &cur_type, &cur, &stop_type, &stop);
1315 seqnum = gst_event_get_seqnum (event);
1317 /* only forward streaming and seeking is possible */
1319 goto unsupported_seek;
1321 /* convert to TIME if needed and possible */
1322 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1326 /* Upstrea seek in bytes will have undefined stop, but qtdemux stores
1327 * the original stop position to use when upstream pushes the new segment
1329 original_stop = stop;
1332 /* find reasonable corresponding BYTE position,
1333 * also try to mind about keyframes, since we can not go back a bit for them
1335 gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, &key_cur, &byte_cur);
1340 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1341 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1344 GST_OBJECT_LOCK (qtdemux);
1345 qtdemux->seek_offset = byte_cur;
1346 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1347 qtdemux->push_seek_start = cur;
1349 qtdemux->push_seek_start = key_cur;
1352 if (stop_type == GST_SEEK_TYPE_NONE) {
1353 qtdemux->push_seek_stop = qtdemux->segment.stop;
1355 qtdemux->push_seek_stop = original_stop;
1357 GST_OBJECT_UNLOCK (qtdemux);
1359 /* BYTE seek event */
1360 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1362 gst_event_set_seqnum (event, seqnum);
1363 res = gst_pad_push_event (qtdemux->sinkpad, event);
1370 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1376 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1381 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1386 /* perform the seek.
1388 * We set all segment_indexes in the streams to unknown and
1389 * adjust the time_position to the desired position. this is enough
1390 * to trigger a segment switch in the streaming thread to start
1391 * streaming from the desired position.
1393 * Keyframe seeking is a little more complicated when dealing with
1394 * segments. Ideally we want to move to the previous keyframe in
1395 * the segment but there might not be a keyframe in the segment. In
1396 * fact, none of the segments could contain a keyframe. We take a
1397 * practical approach: seek to the previous keyframe in the segment,
1398 * if there is none, seek to the beginning of the segment.
1400 * Called with STREAM_LOCK
1403 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1404 guint32 seqnum, GstSeekFlags flags)
1406 gint64 desired_offset;
1409 desired_offset = segment->position;
1411 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1412 GST_TIME_ARGS (desired_offset));
1414 /* may not have enough fragmented info to do this adjustment,
1415 * and we can't scan (and probably should not) at this time with
1416 * possibly flushing upstream */
1417 if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1420 gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, &min_offset, NULL);
1421 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1422 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1423 desired_offset = min_offset;
1426 /* and set all streams to the final position */
1427 gst_flow_combiner_reset (qtdemux->flowcombiner);
1428 for (n = 0; n < qtdemux->n_streams; n++) {
1429 QtDemuxStream *stream = qtdemux->streams[n];
1431 stream->time_position = desired_offset;
1432 stream->accumulated_base = 0;
1433 stream->sample_index = -1;
1434 stream->offset_in_sample = 0;
1435 stream->segment_index = -1;
1436 stream->sent_eos = FALSE;
1437 stream->segment_seqnum = seqnum;
1439 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1440 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1442 segment->position = desired_offset;
1443 segment->time = desired_offset;
1444 if (segment->rate >= 0) {
1445 segment->start = desired_offset;
1447 /* we stop at the end */
1448 if (segment->stop == -1)
1449 segment->stop = segment->duration;
1451 segment->stop = desired_offset;
1454 if (qtdemux->fragmented)
1455 qtdemux->fragmented_seek_pending = TRUE;
1460 /* do a seek in pull based mode */
1462 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1467 GstSeekType cur_type, stop_type;
1471 GstSegment seeksegment;
1473 GstEvent *flush_event;
1476 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1478 gst_event_parse_seek (event, &rate, &format, &flags,
1479 &cur_type, &cur, &stop_type, &stop);
1480 seqnum = gst_event_get_seqnum (event);
1482 /* we have to have a format as the segment format. Try to convert
1484 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1488 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1490 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1494 flush = flags & GST_SEEK_FLAG_FLUSH;
1496 /* stop streaming, either by flushing or by pausing the task */
1498 flush_event = gst_event_new_flush_start ();
1500 gst_event_set_seqnum (flush_event, seqnum);
1501 /* unlock upstream pull_range */
1502 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1503 /* make sure out loop function exits */
1504 gst_qtdemux_push_event (qtdemux, flush_event);
1506 /* non flushing seek, pause the task */
1507 gst_pad_pause_task (qtdemux->sinkpad);
1510 /* wait for streaming to finish */
1511 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1513 /* copy segment, we need this because we still need the old
1514 * segment when we close the current segment. */
1515 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1518 /* configure the segment with the seek variables */
1519 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1520 gst_segment_do_seek (&seeksegment, rate, format, flags,
1521 cur_type, cur, stop_type, stop, &update);
1524 /* now do the seek, this actually never returns FALSE */
1525 gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1527 /* prepare for streaming again */
1529 flush_event = gst_event_new_flush_stop (TRUE);
1531 gst_event_set_seqnum (flush_event, seqnum);
1533 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1534 gst_qtdemux_push_event (qtdemux, flush_event);
1537 /* commit the new segment */
1538 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1540 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1541 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1542 qtdemux->segment.format, qtdemux->segment.position);
1544 gst_message_set_seqnum (msg, seqnum);
1545 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1548 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1549 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1550 qtdemux->sinkpad, NULL);
1552 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1559 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1565 qtdemux_ensure_index (GstQTDemux * qtdemux)
1569 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1571 /* Build complete index */
1572 for (i = 0; i < qtdemux->n_streams; i++) {
1573 QtDemuxStream *stream = qtdemux->streams[i];
1575 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1583 GST_LOG_OBJECT (qtdemux,
1584 "Building complete index of stream %u for seeking failed!", i);
1590 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1593 gboolean res = TRUE;
1594 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1596 switch (GST_EVENT_TYPE (event)) {
1597 case GST_EVENT_SEEK:
1599 #ifndef GST_DISABLE_GST_DEBUG
1600 GstClockTime ts = gst_util_get_timestamp ();
1603 if (qtdemux->upstream_newsegment && qtdemux->fragmented) {
1604 /* seek should be handled by upstream, we might need to re-download fragments */
1605 GST_DEBUG_OBJECT (qtdemux,
1606 "let upstream handle seek for fragmented playback");
1610 /* Build complete index for seeking;
1611 * if not a fragmented file at least */
1612 if (!qtdemux->fragmented)
1613 if (!qtdemux_ensure_index (qtdemux))
1615 #ifndef GST_DISABLE_GST_DEBUG
1616 ts = gst_util_get_timestamp () - ts;
1617 GST_INFO_OBJECT (qtdemux,
1618 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1621 if (qtdemux->pullbased) {
1622 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1623 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1624 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1626 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams
1627 && !qtdemux->fragmented) {
1628 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1630 GST_DEBUG_OBJECT (qtdemux,
1631 "ignoring seek in push mode in current state");
1634 gst_event_unref (event);
1637 case GST_EVENT_NAVIGATION:
1639 gst_event_unref (event);
1643 res = gst_pad_event_default (pad, parent, event);
1653 GST_ERROR_OBJECT (qtdemux, "Index failed");
1654 gst_event_unref (event);
1660 /* stream/index return sample that is min/max w.r.t. byte position,
1661 * time is min/max w.r.t. time of samples,
1662 * the latter need not be time of the former sample */
1664 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1665 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1668 gint64 time, min_time;
1669 QtDemuxStream *stream;
1675 for (n = 0; n < qtdemux->n_streams; ++n) {
1678 gboolean set_sample;
1680 str = qtdemux->streams[n];
1687 i = str->n_samples - 1;
1691 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1692 if (str->samples[i].size == 0)
1695 if (fw && (str->samples[i].offset < byte_pos))
1698 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1701 /* move stream to first available sample */
1703 gst_qtdemux_move_stream (qtdemux, str, i);
1707 /* avoid index from sparse streams since they might be far away */
1709 /* determine min/max time */
1710 time = QTSAMPLE_PTS (str, &str->samples[i]);
1711 if (min_time == -1 || (!fw && time > min_time) ||
1712 (fw && time < min_time)) {
1716 /* determine stream with leading sample, to get its position */
1718 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1719 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1727 /* no sample for this stream, mark eos */
1729 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1740 static QtDemuxStream *
1741 _create_stream (void)
1743 QtDemuxStream *stream;
1745 stream = g_new0 (QtDemuxStream, 1);
1746 /* new streams always need a discont */
1747 stream->discont = TRUE;
1748 /* we enable clipping for raw audio/video streams */
1749 stream->need_clip = FALSE;
1750 stream->need_process = FALSE;
1751 stream->segment_index = -1;
1752 stream->time_position = 0;
1753 stream->sample_index = -1;
1754 stream->offset_in_sample = 0;
1755 stream->new_stream = TRUE;
1756 stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1757 stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1762 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1764 GstStructure *structure;
1765 const gchar *variant;
1766 const GstCaps *mediacaps = NULL;
1768 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1770 structure = gst_caps_get_structure (caps, 0);
1771 variant = gst_structure_get_string (structure, "variant");
1773 if (variant && strcmp (variant, "mss-fragmented") == 0) {
1774 QtDemuxStream *stream;
1775 const GValue *value;
1777 demux->fragmented = TRUE;
1778 demux->mss_mode = TRUE;
1780 if (demux->n_streams > 1) {
1781 /* can't do this, we can only renegotiate for another mss format */
1785 value = gst_structure_get_value (structure, "media-caps");
1788 const GValue *timescale_v;
1790 /* TODO update when stream changes during playback */
1792 if (demux->n_streams == 0) {
1793 stream = _create_stream ();
1794 demux->streams[demux->n_streams] = stream;
1795 demux->n_streams = 1;
1797 stream = demux->streams[0];
1800 timescale_v = gst_structure_get_value (structure, "timescale");
1802 stream->timescale = g_value_get_uint64 (timescale_v);
1804 /* default mss timescale */
1805 stream->timescale = 10000000;
1807 demux->timescale = stream->timescale;
1809 mediacaps = gst_value_get_caps (value);
1810 if (!stream->caps || !gst_caps_is_equal_fixed (mediacaps, stream->caps)) {
1811 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1813 stream->new_caps = TRUE;
1815 gst_caps_replace (&stream->caps, (GstCaps *) mediacaps);
1816 structure = gst_caps_get_structure (mediacaps, 0);
1817 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
1818 stream->subtype = FOURCC_vide;
1820 gst_structure_get_int (structure, "width", &stream->width);
1821 gst_structure_get_int (structure, "height", &stream->height);
1822 gst_structure_get_fraction (structure, "framerate", &stream->fps_n,
1824 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
1826 stream->subtype = FOURCC_soun;
1827 gst_structure_get_int (structure, "channels", &stream->n_channels);
1828 gst_structure_get_int (structure, "rate", &rate);
1829 stream->rate = rate;
1832 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
1834 demux->mss_mode = FALSE;
1841 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
1845 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
1846 gst_pad_stop_task (qtdemux->sinkpad);
1848 if (hard || qtdemux->upstream_newsegment) {
1849 qtdemux->state = QTDEMUX_STATE_INITIAL;
1850 qtdemux->neededbytes = 16;
1851 qtdemux->todrop = 0;
1852 qtdemux->pullbased = FALSE;
1853 qtdemux->posted_redirect = FALSE;
1854 qtdemux->first_mdat = -1;
1855 qtdemux->header_size = 0;
1856 qtdemux->mdatoffset = -1;
1857 qtdemux->restoredata_offset = -1;
1858 if (qtdemux->mdatbuffer)
1859 gst_buffer_unref (qtdemux->mdatbuffer);
1860 if (qtdemux->restoredata_buffer)
1861 gst_buffer_unref (qtdemux->restoredata_buffer);
1862 qtdemux->mdatbuffer = NULL;
1863 qtdemux->restoredata_buffer = NULL;
1864 qtdemux->mdatleft = 0;
1865 if (qtdemux->comp_brands)
1866 gst_buffer_unref (qtdemux->comp_brands);
1867 qtdemux->comp_brands = NULL;
1868 qtdemux->last_moov_offset = -1;
1869 if (qtdemux->moov_node)
1870 g_node_destroy (qtdemux->moov_node);
1871 qtdemux->moov_node = NULL;
1872 qtdemux->moov_node_compressed = NULL;
1873 if (qtdemux->tag_list)
1874 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
1875 qtdemux->tag_list = NULL;
1877 if (qtdemux->element_index)
1878 gst_object_unref (qtdemux->element_index);
1879 qtdemux->element_index = NULL;
1881 qtdemux->major_brand = 0;
1882 if (qtdemux->pending_newsegment)
1883 gst_event_unref (qtdemux->pending_newsegment);
1884 qtdemux->pending_newsegment = NULL;
1885 qtdemux->upstream_newsegment = FALSE;
1886 qtdemux->upstream_seekable = FALSE;
1887 qtdemux->upstream_size = 0;
1889 qtdemux->fragment_start = -1;
1890 qtdemux->fragment_start_offset = -1;
1891 qtdemux->duration = 0;
1892 qtdemux->moof_offset = 0;
1893 qtdemux->chapters_track_id = 0;
1894 qtdemux->have_group_id = FALSE;
1895 qtdemux->group_id = G_MAXUINT;
1897 qtdemux->offset = 0;
1898 gst_adapter_clear (qtdemux->adapter);
1899 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
1902 for (n = 0; n < qtdemux->n_streams; n++) {
1903 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
1904 qtdemux->streams[n] = NULL;
1906 qtdemux->n_streams = 0;
1907 qtdemux->n_video_streams = 0;
1908 qtdemux->n_audio_streams = 0;
1909 qtdemux->n_sub_streams = 0;
1910 qtdemux->exposed = FALSE;
1911 qtdemux->fragmented = FALSE;
1912 qtdemux->mss_mode = FALSE;
1913 gst_caps_replace (&qtdemux->media_caps, NULL);
1914 qtdemux->timescale = 0;
1915 qtdemux->got_moov = FALSE;
1916 } else if (qtdemux->mss_mode) {
1917 gst_flow_combiner_reset (qtdemux->flowcombiner);
1918 for (n = 0; n < qtdemux->n_streams; n++)
1919 gst_qtdemux_stream_clear (qtdemux, qtdemux->streams[n]);
1921 gst_flow_combiner_reset (qtdemux->flowcombiner);
1922 for (n = 0; n < qtdemux->n_streams; n++) {
1923 qtdemux->streams[n]->sent_eos = FALSE;
1924 qtdemux->streams[n]->segment_seqnum = 0;
1925 qtdemux->streams[n]->time_position = 0;
1926 qtdemux->streams[n]->accumulated_base = 0;
1932 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
1935 GstQTDemux *demux = GST_QTDEMUX (parent);
1936 gboolean res = TRUE;
1938 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
1940 switch (GST_EVENT_TYPE (event)) {
1941 case GST_EVENT_SEGMENT:
1944 QtDemuxStream *stream;
1947 GstEvent *segment_event;
1949 /* some debug output */
1950 gst_event_copy_segment (event, &segment);
1951 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
1954 if (segment.format == GST_FORMAT_TIME) {
1955 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
1956 gst_event_replace (&demux->pending_newsegment, event);
1957 demux->upstream_newsegment = TRUE;
1959 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
1960 "not in time format");
1962 /* chain will send initial newsegment after pads have been added */
1963 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
1964 GST_DEBUG_OBJECT (demux, "still starting, eating event");
1969 /* check if this matches a time seek we received previously
1970 * FIXME for backwards compatibility reasons we use the
1971 * seek_offset here to compare. In the future we might want to
1972 * change this to use the seqnum as it uniquely should identify
1973 * the segment that corresponds to the seek. */
1974 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
1975 ", received segment offset %" G_GINT64_FORMAT,
1976 demux->seek_offset, segment.start);
1977 if (segment.format == GST_FORMAT_BYTES
1978 && demux->seek_offset == segment.start) {
1979 GST_OBJECT_LOCK (demux);
1980 offset = segment.start;
1982 segment.format = GST_FORMAT_TIME;
1983 segment.start = demux->push_seek_start;
1984 segment.stop = demux->push_seek_stop;
1985 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
1986 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
1987 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
1988 GST_OBJECT_UNLOCK (demux);
1991 /* we only expect a BYTE segment, e.g. following a seek */
1992 if (segment.format == GST_FORMAT_BYTES) {
1993 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
1994 offset = segment.start;
1996 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
1997 NULL, (gint64 *) & segment.start);
1998 if ((gint64) segment.start < 0)
2001 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2002 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2003 NULL, (gint64 *) & segment.stop);
2004 /* keyframe seeking should already arrange for start >= stop,
2005 * but make sure in other rare cases */
2006 segment.stop = MAX (segment.stop, segment.start);
2008 } else if (segment.format == GST_FORMAT_TIME) {
2011 gst_qtdemux_push_event (demux, gst_event_ref (event));
2012 gst_event_new_new_segment_full (segment.update, segment.rate,
2013 segment.arate, GST_FORMAT_TIME, segment.start, segment.stop,
2015 gst_adapter_clear (demux->adapter);
2016 demux->neededbytes = 16;
2020 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2024 /* accept upstream's notion of segment and distribute along */
2025 segment.format = GST_FORMAT_TIME;
2026 segment.position = segment.time = segment.start;
2027 segment.duration = demux->segment.duration;
2028 segment.base = gst_segment_to_running_time (&demux->segment,
2029 GST_FORMAT_TIME, demux->segment.position);
2031 gst_segment_copy_into (&segment, &demux->segment);
2032 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2033 segment_event = gst_event_new_segment (&segment);
2034 gst_event_set_seqnum (segment_event, gst_event_get_seqnum (event));
2035 gst_qtdemux_push_event (demux, segment_event);
2037 /* clear leftover in current segment, if any */
2038 gst_adapter_clear (demux->adapter);
2039 /* set up streaming thread */
2040 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx, NULL);
2041 demux->offset = offset;
2043 demux->todrop = stream->samples[idx].offset - offset;
2044 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2046 /* set up for EOS */
2047 if (demux->upstream_newsegment) {
2048 demux->neededbytes = 16;
2050 demux->neededbytes = -1;
2055 gst_event_unref (event);
2059 case GST_EVENT_FLUSH_STOP:
2063 dur = demux->segment.duration;
2064 gst_qtdemux_reset (demux, FALSE);
2065 demux->segment.duration = dur;
2069 /* If we are in push mode, and get an EOS before we've seen any streams,
2070 * then error out - we have nowhere to send the EOS */
2071 if (!demux->pullbased) {
2073 gboolean has_valid_stream = FALSE;
2074 for (i = 0; i < demux->n_streams; i++) {
2075 if (demux->streams[i]->pad != NULL) {
2076 has_valid_stream = TRUE;
2080 if (!has_valid_stream)
2081 gst_qtdemux_post_no_playable_stream_error (demux);
2083 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2084 (guint) gst_adapter_available (demux->adapter));
2085 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2091 case GST_EVENT_CAPS:{
2092 GstCaps *caps = NULL;
2094 gst_event_parse_caps (event, &caps);
2095 gst_qtdemux_setcaps (demux, caps);
2097 gst_event_unref (event);
2104 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2112 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2114 GstQTDemux *demux = GST_QTDEMUX (element);
2116 GST_OBJECT_LOCK (demux);
2117 if (demux->element_index)
2118 gst_object_unref (demux->element_index);
2120 demux->element_index = gst_object_ref (index);
2122 demux->element_index = NULL;
2124 GST_OBJECT_UNLOCK (demux);
2125 /* object lock might be taken again */
2127 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2128 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2129 demux->element_index, demux->index_id);
2133 gst_qtdemux_get_index (GstElement * element)
2135 GstIndex *result = NULL;
2136 GstQTDemux *demux = GST_QTDEMUX (element);
2138 GST_OBJECT_LOCK (demux);
2139 if (demux->element_index)
2140 result = gst_object_ref (demux->element_index);
2141 GST_OBJECT_UNLOCK (demux);
2143 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2150 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2152 g_free ((gpointer) stream->stco.data);
2153 stream->stco.data = NULL;
2154 g_free ((gpointer) stream->stsz.data);
2155 stream->stsz.data = NULL;
2156 g_free ((gpointer) stream->stsc.data);
2157 stream->stsc.data = NULL;
2158 g_free ((gpointer) stream->stts.data);
2159 stream->stts.data = NULL;
2160 g_free ((gpointer) stream->stss.data);
2161 stream->stss.data = NULL;
2162 g_free ((gpointer) stream->stps.data);
2163 stream->stps.data = NULL;
2164 g_free ((gpointer) stream->ctts.data);
2165 stream->ctts.data = NULL;
2169 gst_qtdemux_stream_flush_samples_data (GstQTDemux * qtdemux,
2170 QtDemuxStream * stream)
2172 g_free (stream->samples);
2173 stream->samples = NULL;
2174 g_free (stream->segments);
2175 stream->segments = NULL;
2176 gst_qtdemux_stbl_free (stream);
2179 g_free (stream->ra_entries);
2180 stream->ra_entries = NULL;
2181 stream->n_ra_entries = 0;
2183 stream->sample_index = -1;
2184 stream->stbl_index = -1;
2185 stream->n_samples = 0;
2186 stream->time_position = 0;
2187 stream->segment_index = -1;
2188 stream->accumulated_base = 0;
2192 gst_qtdemux_stream_clear (GstQTDemux * qtdemux, QtDemuxStream * stream)
2194 if (stream->allocator)
2195 gst_object_unref (stream->allocator);
2196 while (stream->buffers) {
2197 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2198 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2200 if (stream->rgb8_palette) {
2201 gst_memory_unref (stream->rgb8_palette);
2202 stream->rgb8_palette = NULL;
2205 if (stream->pending_tags)
2206 gst_tag_list_unref (stream->pending_tags);
2207 stream->pending_tags = NULL;
2208 g_free (stream->redirect_uri);
2209 stream->redirect_uri = NULL;
2210 stream->sent_eos = FALSE;
2211 stream->sparse = FALSE;
2213 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
2217 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
2219 gst_qtdemux_stream_clear (qtdemux, stream);
2221 gst_caps_unref (stream->caps);
2222 stream->caps = NULL;
2224 gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
2225 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, stream->pad);
2231 gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int i)
2233 g_assert (i >= 0 && i < qtdemux->n_streams && qtdemux->streams[i] != NULL);
2235 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[i]);
2236 qtdemux->streams[i] = qtdemux->streams[qtdemux->n_streams - 1];
2237 qtdemux->streams[qtdemux->n_streams - 1] = NULL;
2238 qtdemux->n_streams--;
2241 static GstStateChangeReturn
2242 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2244 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2245 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2247 switch (transition) {
2248 case GST_STATE_CHANGE_PAUSED_TO_READY:
2254 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2256 switch (transition) {
2257 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2258 gst_qtdemux_reset (qtdemux, TRUE);
2269 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2271 /* counts as header data */
2272 qtdemux->header_size += length;
2274 /* only consider at least a sufficiently complete ftyp atom */
2278 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2279 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2280 GST_FOURCC_ARGS (qtdemux->major_brand));
2281 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2282 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2287 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist,
2288 GstTagList * xmptaglist)
2290 /* Strip out bogus fields */
2292 if (gst_tag_list_get_scope (taglist) == GST_TAG_SCOPE_GLOBAL) {
2293 gst_tag_list_remove_tag (xmptaglist, GST_TAG_VIDEO_CODEC);
2294 gst_tag_list_remove_tag (xmptaglist, GST_TAG_AUDIO_CODEC);
2296 gst_tag_list_remove_tag (xmptaglist, GST_TAG_CONTAINER_FORMAT);
2299 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, xmptaglist);
2301 /* prioritize native tags using _KEEP mode */
2302 gst_tag_list_insert (taglist, xmptaglist, GST_TAG_MERGE_KEEP);
2303 gst_tag_list_unref (xmptaglist);
2308 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2310 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2311 0x97, 0xA9, 0x42, 0xE8,
2312 0x9C, 0x71, 0x99, 0x94,
2313 0x91, 0xE3, 0xAF, 0xAC
2315 static const guint8 playready_uuid[] = {
2316 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2317 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2321 /* counts as header data */
2322 qtdemux->header_size += length;
2324 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2326 if (length <= offset + 16) {
2327 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2331 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2333 GstTagList *taglist;
2335 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2336 length - offset - 16, NULL);
2337 taglist = gst_tag_list_from_xmp_buffer (buf);
2338 gst_buffer_unref (buf);
2340 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
2342 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
2344 const gunichar2 *s_utf16;
2347 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
2348 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
2349 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
2350 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
2354 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
2355 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
2358 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
2359 GST_READ_UINT32_LE (buffer + offset),
2360 GST_READ_UINT32_LE (buffer + offset + 4),
2361 GST_READ_UINT32_LE (buffer + offset + 8),
2362 GST_READ_UINT32_LE (buffer + offset + 12));
2367 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2369 GstSidxParser sidx_parser;
2370 GstIsoffParserResult res;
2373 gst_isoff_qt_sidx_parser_init (&sidx_parser);
2376 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
2378 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
2379 if (res == GST_ISOFF_QT_PARSER_DONE) {
2380 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
2382 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
2385 /* caller verifies at least 8 bytes in buf */
2387 extract_initial_length_and_fourcc (const guint8 * data, guint size,
2388 guint64 * plength, guint32 * pfourcc)
2393 length = QT_UINT32 (data);
2394 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2395 fourcc = QT_FOURCC (data + 4);
2396 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
2399 length = G_MAXUINT64;
2400 } else if (length == 1 && size >= 16) {
2401 /* this means we have an extended size, which is the 64 bit value of
2402 * the next 8 bytes */
2403 length = QT_UINT64 (data + 8);
2404 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2414 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
2416 guint32 version = 0;
2417 GstClockTime duration = 0;
2419 if (!gst_byte_reader_get_uint32_be (br, &version))
2424 if (!gst_byte_reader_get_uint64_be (br, &duration))
2429 if (!gst_byte_reader_get_uint32_be (br, &dur))
2434 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
2435 qtdemux->duration = duration;
2441 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
2447 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
2448 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
2450 if (!stream->parsed_trex && qtdemux->moov_node) {
2452 GstByteReader trex_data;
2454 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
2456 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
2459 guint32 id = 0, dur = 0, size = 0, flags = 0, dummy = 0;
2461 /* skip version/flags */
2462 if (!gst_byte_reader_skip (&trex_data, 4))
2464 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
2466 if (id != stream->track_id)
2468 /* sample description index; ignore */
2469 if (!gst_byte_reader_get_uint32_be (&trex_data, &dummy))
2471 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2473 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
2475 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
2478 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
2479 "duration %d, size %d, flags 0x%x", stream->track_id,
2482 stream->parsed_trex = TRUE;
2483 stream->def_sample_duration = dur;
2484 stream->def_sample_size = size;
2485 stream->def_sample_flags = flags;
2488 /* iterate all siblings */
2489 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
2495 *ds_duration = stream->def_sample_duration;
2496 *ds_size = stream->def_sample_size;
2497 *ds_flags = stream->def_sample_flags;
2499 /* even then, above values are better than random ... */
2500 if (G_UNLIKELY (!stream->parsed_trex)) {
2501 GST_WARNING_OBJECT (qtdemux,
2502 "failed to find fragment defaults for stream %d", stream->track_id);
2509 /* This method should be called whenever a more accurate duration might
2510 * have been found. It will update all relevant variables if/where needed
2513 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
2517 GstClockTime prevdur;
2519 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
2521 if (movdur > qtdemux->duration) {
2522 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
2523 GST_DEBUG_OBJECT (qtdemux,
2524 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
2525 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
2526 qtdemux->duration = movdur;
2527 GST_DEBUG_OBJECT (qtdemux,
2528 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
2529 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
2530 GST_TIME_ARGS (qtdemux->segment.stop));
2531 if (qtdemux->segment.duration == prevdur) {
2532 /* If the current segment has duration/stop identical to previous duration
2533 * update them also (because they were set at that point in time with
2534 * the wrong duration */
2535 /* We convert the value *from* the timescale version to avoid rounding errors */
2536 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
2537 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
2538 qtdemux->segment.duration = fixeddur;
2539 qtdemux->segment.stop = fixeddur;
2542 for (i = 0; i < qtdemux->n_streams; i++) {
2543 QtDemuxStream *stream = qtdemux->streams[i];
2545 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
2546 if (movdur > stream->duration) {
2547 GST_DEBUG_OBJECT (qtdemux,
2548 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
2549 GST_TIME_ARGS (duration));
2550 stream->duration = movdur;
2551 if (stream->dummy_segment) {
2552 /* Update all dummy values to new duration */
2553 stream->segments[0].stop_time = duration;
2554 stream->segments[0].duration = duration;
2555 stream->segments[0].media_stop = duration;
2563 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
2564 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
2565 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
2566 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts)
2568 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
2570 gint32 data_offset = 0;
2571 guint32 flags = 0, first_flags = 0, samples_count = 0;
2574 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
2575 QtDemuxSample *sample;
2576 gboolean ismv = FALSE;
2578 GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
2579 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
2580 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
2581 d_sample_size, d_sample_flags, *base_offset, decode_ts);
2583 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
2584 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
2588 /* presence of stss or not can't really tell us much,
2589 * and flags and so on tend to be marginally reliable in these files */
2590 if (stream->subtype == FOURCC_soun) {
2591 GST_DEBUG_OBJECT (qtdemux,
2592 "sound track in fragmented file; marking all keyframes");
2593 stream->all_keyframe = TRUE;
2596 if (!gst_byte_reader_skip (trun, 1) ||
2597 !gst_byte_reader_get_uint24_be (trun, &flags))
2600 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
2603 if (flags & TR_DATA_OFFSET) {
2604 /* note this is really signed */
2605 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
2607 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
2608 /* default base offset = first byte of moof */
2609 if (*base_offset == -1) {
2610 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
2611 *base_offset = moof_offset;
2613 *running_offset = *base_offset + data_offset;
2615 /* if no offset at all, that would mean data starts at moof start,
2616 * which is a bit wrong and is ismv crappy way, so compensate
2617 * assuming data is in mdat following moof */
2618 if (*base_offset == -1) {
2619 *base_offset = moof_offset + moof_length + 8;
2620 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
2623 if (*running_offset == -1)
2624 *running_offset = *base_offset;
2627 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
2629 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
2630 data_offset, flags, samples_count);
2632 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2633 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
2634 GST_DEBUG_OBJECT (qtdemux,
2635 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
2636 flags ^= TR_FIRST_SAMPLE_FLAGS;
2638 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
2640 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
2644 /* FIXME ? spec says other bits should also be checked to determine
2645 * entry size (and prefix size for that matter) */
2647 dur_offset = size_offset = 0;
2648 if (flags & TR_SAMPLE_DURATION) {
2649 GST_LOG_OBJECT (qtdemux, "entry duration present");
2650 dur_offset = entry_size;
2653 if (flags & TR_SAMPLE_SIZE) {
2654 GST_LOG_OBJECT (qtdemux, "entry size present");
2655 size_offset = entry_size;
2658 if (flags & TR_SAMPLE_FLAGS) {
2659 GST_LOG_OBJECT (qtdemux, "entry flags present");
2660 flags_offset = entry_size;
2663 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2664 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
2665 ct_offset = entry_size;
2669 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
2671 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
2673 if (stream->n_samples >=
2674 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
2677 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
2678 stream->n_samples, (guint) sizeof (QtDemuxSample),
2679 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
2681 /* create a new array of samples if it's the first sample parsed */
2682 if (stream->n_samples == 0)
2683 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
2684 /* or try to reallocate it with space enough to insert the new samples */
2686 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
2687 stream->n_samples + samples_count);
2688 if (stream->samples == NULL)
2691 if (qtdemux->fragment_start != -1) {
2692 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
2693 qtdemux->fragment_start = -1;
2695 if (G_UNLIKELY (stream->n_samples == 0)) {
2696 if (decode_ts > 0) {
2697 timestamp = decode_ts;
2698 } else if (stream->pending_seek != NULL) {
2699 /* if we don't have a timestamp from a tfdt box, we'll use the one
2700 * from the mfra seek table */
2701 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
2702 GST_TIME_ARGS (stream->pending_seek->ts));
2704 /* FIXME: this is not fully correct, the timestamp refers to the random
2705 * access sample refered to in the tfra entry, which may not necessarily
2706 * be the first sample in the tfrag/trun (but hopefully/usually is) */
2707 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
2712 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
2713 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
2714 GST_TIME_ARGS (gst_ts));
2716 /* subsequent fragments extend stream */
2718 stream->samples[stream->n_samples - 1].timestamp +
2719 stream->samples[stream->n_samples - 1].duration;
2721 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
2722 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
2723 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
2727 sample = stream->samples + stream->n_samples;
2728 for (i = 0; i < samples_count; i++) {
2729 guint32 dur, size, sflags, ct;
2731 /* first read sample data */
2732 if (flags & TR_SAMPLE_DURATION) {
2733 dur = QT_UINT32 (data + dur_offset);
2735 dur = d_sample_duration;
2737 if (flags & TR_SAMPLE_SIZE) {
2738 size = QT_UINT32 (data + size_offset);
2740 size = d_sample_size;
2742 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2744 sflags = first_flags;
2746 sflags = d_sample_flags;
2748 } else if (flags & TR_SAMPLE_FLAGS) {
2749 sflags = QT_UINT32 (data + flags_offset);
2751 sflags = d_sample_flags;
2753 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2754 ct = QT_UINT32 (data + ct_offset);
2760 /* fill the sample information */
2761 sample->offset = *running_offset;
2762 sample->pts_offset = ct;
2763 sample->size = size;
2764 sample->timestamp = timestamp;
2765 sample->duration = dur;
2766 /* sample-is-difference-sample */
2767 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
2768 * now idea how it relates to bitfield other than massive LE/BE confusion */
2769 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
2770 *running_offset += size;
2775 /* Update total duration if needed */
2776 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
2778 stream->n_samples += samples_count;
2780 if (stream->pending_seek != NULL)
2781 stream->pending_seek = NULL;
2787 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
2792 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
2798 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
2799 "be larger than %uMB (broken file?)", stream->n_samples,
2800 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
2805 /* find stream with @id */
2806 static inline QtDemuxStream *
2807 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
2809 QtDemuxStream *stream;
2813 if (G_UNLIKELY (!id)) {
2814 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
2818 /* try to get it fast and simple */
2819 if (G_LIKELY (id <= qtdemux->n_streams)) {
2820 stream = qtdemux->streams[id - 1];
2821 if (G_LIKELY (stream->track_id == id))
2825 /* linear search otherwise */
2826 for (i = 0; i < qtdemux->n_streams; i++) {
2827 stream = qtdemux->streams[i];
2828 if (stream->track_id == id)
2831 if (qtdemux->mss_mode) {
2832 /* mss should have only 1 stream anyway */
2833 return qtdemux->streams[0];
2840 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
2841 guint32 * fragment_number)
2843 if (!gst_byte_reader_skip (mfhd, 4))
2845 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
2850 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
2856 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
2857 QtDemuxStream ** stream, guint32 * default_sample_duration,
2858 guint32 * default_sample_size, guint32 * default_sample_flags,
2859 gint64 * base_offset)
2862 guint32 track_id = 0;
2864 if (!gst_byte_reader_skip (tfhd, 1) ||
2865 !gst_byte_reader_get_uint24_be (tfhd, &flags))
2868 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
2871 *stream = qtdemux_find_stream (qtdemux, track_id);
2872 if (G_UNLIKELY (!*stream))
2873 goto unknown_stream;
2875 if (flags & TF_BASE_DATA_OFFSET)
2876 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
2879 /* obtain stream defaults */
2880 qtdemux_parse_trex (qtdemux, *stream,
2881 default_sample_duration, default_sample_size, default_sample_flags);
2883 /* FIXME: Handle TF_SAMPLE_DESCRIPTION_INDEX properly */
2884 if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
2885 if (!gst_byte_reader_skip (tfhd, 4))
2888 if (flags & TF_DEFAULT_SAMPLE_DURATION)
2889 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
2892 if (flags & TF_DEFAULT_SAMPLE_SIZE)
2893 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
2896 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
2897 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
2904 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
2909 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
2915 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
2916 guint64 * decode_time)
2918 guint32 version = 0;
2920 if (!gst_byte_reader_get_uint32_be (br, &version))
2925 if (!gst_byte_reader_get_uint64_be (br, decode_time))
2928 guint32 dec_time = 0;
2929 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
2931 *decode_time = dec_time;
2934 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
2941 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
2947 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
2948 guint64 moof_offset, QtDemuxStream * stream)
2950 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
2951 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
2952 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
2953 gint64 base_offset, running_offset;
2956 /* NOTE @stream ignored */
2958 moof_node = g_node_new ((guint8 *) buffer);
2959 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
2960 qtdemux_node_dump (qtdemux, moof_node);
2962 /* Get fragment number from mfhd and check it's valid */
2964 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
2965 if (mfhd_node == NULL)
2967 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
2969 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
2971 /* unknown base_offset to start with */
2972 base_offset = running_offset = -1;
2973 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
2975 guint64 decode_time = 0;
2977 /* Fragment Header node */
2979 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
2983 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
2984 &ds_size, &ds_flags, &base_offset))
2987 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
2990 GstClockTime decode_time_ts;
2992 /* We'll use decode_time to interpolate timestamps
2993 * in case the input timestamps are missing */
2994 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
2996 decode_time_ts = QTSTREAMTIME_TO_GSTTIME (stream, decode_time);
2998 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
2999 " (%" GST_TIME_FORMAT ")", decode_time,
3000 GST_TIME_ARGS (decode_time_ts));
3002 /* Discard the fragment buffer timestamp info to avoid using it.
3003 * Rely on tfdt instead as it is more accurate than the timestamp
3004 * that is fetched from a manifest/playlist and is usually
3006 qtdemux->fragment_start = -1;
3009 if (G_UNLIKELY (!stream)) {
3010 /* we lost track of offset, we'll need to regain it,
3011 * but can delay complaining until later or avoid doing so altogether */
3015 if (G_UNLIKELY (base_offset < -1))
3017 /* Track Run node */
3019 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
3022 qtdemux_parse_trun (qtdemux, &trun_data, stream,
3023 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
3024 &running_offset, decode_time);
3025 /* iterate all siblings */
3026 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
3029 /* if no new base_offset provided for next traf,
3030 * base is end of current traf */
3031 base_offset = running_offset;
3032 running_offset = -1;
3034 /* iterate all siblings */
3035 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
3037 g_node_destroy (moof_node);
3042 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
3047 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
3052 GST_DEBUG_OBJECT (qtdemux, "lost offset");
3057 g_node_destroy (moof_node);
3058 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
3059 (_("This file is corrupt and cannot be played.")), (NULL));
3065 /* might be used if some day we actually use mfra & co
3066 * for random access to fragments,
3067 * but that will require quite some modifications and much less relying
3068 * on a sample array */
3072 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
3074 QtDemuxStream *stream;
3075 guint32 ver_flags, track_id, len, num_entries, i;
3076 guint value_size, traf_size, trun_size, sample_size;
3077 guint64 time = 0, moof_offset = 0;
3079 GstBuffer *buf = NULL;
3084 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
3086 if (!gst_byte_reader_skip (&tfra, 8))
3089 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
3092 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
3093 || !gst_byte_reader_get_uint32_be (&tfra, &len)
3094 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
3097 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
3099 stream = qtdemux_find_stream (qtdemux, track_id);
3101 goto unknown_trackid;
3103 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
3104 sample_size = (len & 3) + 1;
3105 trun_size = ((len & 12) >> 2) + 1;
3106 traf_size = ((len & 48) >> 4) + 1;
3108 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
3109 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
3111 if (num_entries == 0)
3114 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
3115 value_size + value_size + traf_size + trun_size + sample_size))
3118 g_free (stream->ra_entries);
3119 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
3120 stream->n_ra_entries = num_entries;
3122 for (i = 0; i < num_entries; i++) {
3123 qt_atom_parser_get_offset (&tfra, value_size, &time);
3124 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
3125 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
3126 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
3127 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
3129 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
3131 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
3132 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
3134 stream->ra_entries[i].ts = time;
3135 stream->ra_entries[i].moof_offset = moof_offset;
3137 /* don't want to go through the entire file and read all moofs at startup */
3139 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
3140 if (ret != GST_FLOW_OK)
3142 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
3143 moof_offset, stream);
3144 gst_buffer_unref (buf);
3148 check_update_duration (qtdemux, time);
3155 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
3160 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
3165 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
3171 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
3173 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
3174 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
3175 GstBuffer *mfro = NULL, *mfra = NULL;
3177 gboolean ret = FALSE;
3178 GNode *mfra_node, *tfra_node;
3179 guint64 mfra_offset = 0;
3180 guint32 fourcc, mfra_size;
3183 /* query upstream size in bytes */
3184 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
3185 goto size_query_failed;
3187 /* mfro box should be at the very end of the file */
3188 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
3189 if (flow != GST_FLOW_OK)
3192 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
3194 fourcc = QT_FOURCC (mfro_map.data + 4);
3195 if (fourcc != FOURCC_mfro)
3198 GST_INFO_OBJECT (qtdemux, "Found mfro box");
3199 if (mfro_map.size < 16)
3200 goto invalid_mfro_size;
3202 mfra_size = QT_UINT32 (mfro_map.data + 12);
3203 if (mfra_size >= len)
3204 goto invalid_mfra_size;
3206 mfra_offset = len - mfra_size;
3208 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
3209 mfra_offset, mfra_size);
3211 /* now get and parse mfra box */
3212 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
3213 if (flow != GST_FLOW_OK)
3216 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
3218 mfra_node = g_node_new ((guint8 *) mfra_map.data);
3219 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
3221 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
3224 qtdemux_parse_tfra (qtdemux, tfra_node);
3225 /* iterate all siblings */
3226 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
3228 g_node_destroy (mfra_node);
3230 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
3236 if (mfro_map.memory != NULL)
3237 gst_buffer_unmap (mfro, &mfro_map);
3238 gst_buffer_unref (mfro);
3241 if (mfra_map.memory != NULL)
3242 gst_buffer_unmap (mfra, &mfra_map);
3243 gst_buffer_unref (mfra);
3250 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
3255 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
3260 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
3265 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
3271 add_offset (guint64 offset, guint64 advance)
3273 /* Avoid 64-bit overflow by clamping */
3274 if (offset > G_MAXUINT64 - advance)
3276 return offset + advance;
3279 static GstFlowReturn
3280 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
3284 GstBuffer *buf = NULL;
3285 GstFlowReturn ret = GST_FLOW_OK;
3286 guint64 cur_offset = qtdemux->offset;
3289 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
3290 if (G_UNLIKELY (ret != GST_FLOW_OK))
3292 gst_buffer_map (buf, &map, GST_MAP_READ);
3293 if (G_LIKELY (map.size >= 8))
3294 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
3295 gst_buffer_unmap (buf, &map);
3296 gst_buffer_unref (buf);
3298 /* maybe we already got most we needed, so only consider this eof */
3299 if (G_UNLIKELY (length == 0)) {
3300 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
3301 (_("Invalid atom size.")),
3302 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
3303 GST_FOURCC_ARGS (fourcc)));
3310 /* record for later parsing when needed */
3311 if (!qtdemux->moof_offset) {
3312 qtdemux->moof_offset = qtdemux->offset;
3314 if (qtdemux_pull_mfro_mfra (qtdemux)) {
3317 if (qtdemux->got_moov) {
3318 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
3329 GST_LOG_OBJECT (qtdemux,
3330 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
3331 GST_FOURCC_ARGS (fourcc), cur_offset);
3332 qtdemux->offset = add_offset (qtdemux->offset, length);
3337 GstBuffer *moov = NULL;
3339 if (qtdemux->got_moov) {
3340 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
3341 qtdemux->offset = add_offset (qtdemux->offset, length);
3345 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
3346 if (ret != GST_FLOW_OK)
3348 gst_buffer_map (moov, &map, GST_MAP_READ);
3350 if (length != map.size) {
3351 /* Some files have a 'moov' atom at the end of the file which contains
3352 * a terminal 'free' atom where the body of the atom is missing.
3353 * Check for, and permit, this special case.
3355 if (map.size >= 8) {
3356 guint8 *final_data = map.data + (map.size - 8);
3357 guint32 final_length = QT_UINT32 (final_data);
3358 guint32 final_fourcc = QT_FOURCC (final_data + 4);
3360 if (final_fourcc == FOURCC_free
3361 && map.size + final_length - 8 == length) {
3362 /* Ok, we've found that special case. Allocate a new buffer with
3363 * that free atom actually present. */
3364 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
3365 gst_buffer_fill (newmoov, 0, map.data, map.size);
3366 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
3367 gst_buffer_unmap (moov, &map);
3368 gst_buffer_unref (moov);
3370 gst_buffer_map (moov, &map, GST_MAP_READ);
3375 if (length != map.size) {
3376 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
3377 (_("This file is incomplete and cannot be played.")),
3378 ("We got less than expected (received %" G_GSIZE_FORMAT
3379 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
3380 (guint) length, cur_offset));
3381 gst_buffer_unmap (moov, &map);
3382 gst_buffer_unref (moov);
3383 ret = GST_FLOW_ERROR;
3386 qtdemux->offset += length;
3388 qtdemux_parse_moov (qtdemux, map.data, length);
3389 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
3391 qtdemux_parse_tree (qtdemux);
3392 g_node_destroy (qtdemux->moov_node);
3393 gst_buffer_unmap (moov, &map);
3394 gst_buffer_unref (moov);
3395 qtdemux->moov_node = NULL;
3396 qtdemux->got_moov = TRUE;
3402 GstBuffer *ftyp = NULL;
3404 /* extract major brand; might come in handy for ISO vs QT issues */
3405 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
3406 if (ret != GST_FLOW_OK)
3408 qtdemux->offset += length;
3409 gst_buffer_map (ftyp, &map, GST_MAP_READ);
3410 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
3411 gst_buffer_unmap (ftyp, &map);
3412 gst_buffer_unref (ftyp);
3417 GstBuffer *uuid = NULL;
3419 /* uuid are extension atoms */
3420 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
3421 if (ret != GST_FLOW_OK)
3423 qtdemux->offset += length;
3424 gst_buffer_map (uuid, &map, GST_MAP_READ);
3425 qtdemux_parse_uuid (qtdemux, map.data, map.size);
3426 gst_buffer_unmap (uuid, &map);
3427 gst_buffer_unref (uuid);
3432 GstBuffer *sidx = NULL;
3433 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
3434 if (ret != GST_FLOW_OK)
3436 qtdemux->offset += length;
3437 gst_buffer_map (sidx, &map, GST_MAP_READ);
3438 qtdemux_parse_sidx (qtdemux, map.data, map.size);
3439 gst_buffer_unmap (sidx, &map);
3440 gst_buffer_unref (sidx);
3445 GstBuffer *unknown = NULL;
3447 GST_LOG_OBJECT (qtdemux,
3448 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
3449 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
3451 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
3452 if (ret != GST_FLOW_OK)
3454 gst_buffer_map (unknown, &map, GST_MAP_READ);
3455 GST_MEMDUMP ("Unknown tag", map.data, map.size);
3456 gst_buffer_unmap (unknown, &map);
3457 gst_buffer_unref (unknown);
3458 qtdemux->offset += length;
3464 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
3465 /* digested all data, show what we have */
3466 qtdemux_prepare_streams (qtdemux);
3467 ret = qtdemux_expose_streams (qtdemux);
3469 qtdemux->state = QTDEMUX_STATE_MOVIE;
3470 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
3477 /* Seeks to the previous keyframe of the indexed stream and
3478 * aligns other streams with respect to the keyframe timestamp
3479 * of indexed stream. Only called in case of Reverse Playback
3481 static GstFlowReturn
3482 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
3485 guint32 seg_idx = 0, k_index = 0;
3486 guint32 ref_seg_idx, ref_k_index;
3487 GstClockTime k_pos = 0, last_stop = 0;
3488 QtDemuxSegment *seg = NULL;
3489 QtDemuxStream *ref_str = NULL;
3490 guint64 seg_media_start_mov; /* segment media start time in mov format */
3493 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
3494 * and finally align all the other streams on that timestamp with their
3495 * respective keyframes */
3496 for (n = 0; n < qtdemux->n_streams; n++) {
3497 QtDemuxStream *str = qtdemux->streams[n];
3499 /* No candidate yet, take the first stream */
3505 /* So that stream has a segment, we prefer video streams */
3506 if (str->subtype == FOURCC_vide) {
3512 if (G_UNLIKELY (!ref_str)) {
3513 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
3517 if (G_UNLIKELY (!ref_str->from_sample)) {
3518 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
3522 /* So that stream has been playing from from_sample to to_sample. We will
3523 * get the timestamp of the previous sample and search for a keyframe before
3524 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
3525 if (ref_str->subtype == FOURCC_vide) {
3526 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
3527 ref_str->from_sample - 1);
3529 if (ref_str->from_sample >= 10)
3530 k_index = ref_str->from_sample - 10;
3536 ref_str->samples[k_index].timestamp +
3537 ref_str->samples[k_index].pts_offset;
3539 /* get current segment for that stream */
3540 seg = &ref_str->segments[ref_str->segment_index];
3541 /* Use segment start in original timescale for comparisons */
3542 seg_media_start_mov = seg->trak_media_start;
3544 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
3545 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT "\n",
3546 k_index, target_ts, seg_media_start_mov,
3547 GST_TIME_ARGS (seg->media_start));
3549 /* Crawl back through segments to find the one containing this I frame */
3550 while (target_ts < seg_media_start_mov) {
3551 GST_DEBUG_OBJECT (qtdemux,
3552 "keyframe position (sample %u) is out of segment %u " " target %"
3553 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
3554 ref_str->segment_index, target_ts, seg_media_start_mov);
3556 if (G_UNLIKELY (!ref_str->segment_index)) {
3557 /* Reached first segment, let's consider it's EOS */
3560 ref_str->segment_index--;
3561 seg = &ref_str->segments[ref_str->segment_index];
3562 /* Use segment start in original timescale for comparisons */
3563 seg_media_start_mov = seg->trak_media_start;
3565 /* Calculate time position of the keyframe and where we should stop */
3567 QTSTREAMTIME_TO_GSTTIME (ref_str,
3568 target_ts - seg->trak_media_start) + seg->time;
3570 QTSTREAMTIME_TO_GSTTIME (ref_str,
3571 ref_str->samples[ref_str->from_sample].timestamp -
3572 seg->trak_media_start) + seg->time;
3574 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
3575 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
3576 k_index, GST_TIME_ARGS (k_pos));
3578 /* Set last_stop with the keyframe timestamp we pushed of that stream */
3579 qtdemux->segment.position = last_stop;
3580 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
3581 GST_TIME_ARGS (last_stop));
3583 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
3584 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
3588 ref_seg_idx = ref_str->segment_index;
3589 ref_k_index = k_index;
3591 /* Align them all on this */
3592 for (n = 0; n < qtdemux->n_streams; n++) {
3594 GstClockTime seg_time = 0;
3595 QtDemuxStream *str = qtdemux->streams[n];
3597 /* aligning reference stream again might lead to backing up to yet another
3598 * keyframe (due to timestamp rounding issues),
3599 * potentially putting more load on downstream; so let's try to avoid */
3600 if (str == ref_str) {
3601 seg_idx = ref_seg_idx;
3602 seg = &str->segments[seg_idx];
3603 k_index = ref_k_index;
3604 GST_DEBUG_OBJECT (qtdemux, "reference stream %d segment %d, "
3605 "sample at index %d", n, ref_str->segment_index, k_index);
3607 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
3608 GST_DEBUG_OBJECT (qtdemux,
3609 "stream %d align segment %d for keyframe pos %" GST_TIME_FORMAT, n,
3610 seg_idx, GST_TIME_ARGS (k_pos));
3612 /* get segment and time in the segment */
3613 seg = &str->segments[seg_idx];
3614 seg_time = k_pos - seg->time;
3616 /* get the media time in the segment.
3617 * No adjustment for empty "filler" segments */
3618 if (seg->media_start != GST_CLOCK_TIME_NONE)
3619 seg_time += seg->media_start;
3621 /* get the index of the sample with media time */
3622 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
3623 GST_DEBUG_OBJECT (qtdemux,
3624 "stream %d sample for %" GST_TIME_FORMAT " at %u", n,
3625 GST_TIME_ARGS (seg_time), index);
3627 /* find previous keyframe */
3628 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index);
3631 /* Remember until where we want to go */
3632 str->to_sample = str->from_sample - 1;
3633 /* Define our time position */
3635 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
3636 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
3637 if (seg->media_start != GST_CLOCK_TIME_NONE)
3638 str->time_position -= seg->media_start;
3640 /* Now seek back in time */
3641 gst_qtdemux_move_stream (qtdemux, str, k_index);
3642 GST_DEBUG_OBJECT (qtdemux, "stream %d keyframe at %u, time position %"
3643 GST_TIME_FORMAT " playing from sample %u to %u", n, k_index,
3644 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
3650 return GST_FLOW_EOS;
3653 /* activate the given segment number @seg_idx of @stream at time @offset.
3654 * @offset is an absolute global position over all the segments.
3656 * This will push out a NEWSEGMENT event with the right values and
3657 * position the stream index to the first decodable sample before
3663 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
3664 guint32 seg_idx, GstClockTime offset)
3667 QtDemuxSegment *segment;
3668 guint32 index, kf_index;
3669 GstClockTime seg_time;
3670 GstClockTime start, stop, time;
3673 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
3674 seg_idx, GST_TIME_ARGS (offset));
3676 /* update the current segment */
3677 stream->segment_index = seg_idx;
3679 /* get the segment */
3680 segment = &stream->segments[seg_idx];
3682 if (G_UNLIKELY (offset < segment->time)) {
3683 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
3684 GST_TIME_ARGS (segment->time));
3688 /* segment lies beyond total indicated duration */
3689 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
3690 segment->time > qtdemux->segment.duration)) {
3691 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
3692 " < segment->time %" GST_TIME_FORMAT,
3693 GST_TIME_ARGS (qtdemux->segment.duration),
3694 GST_TIME_ARGS (segment->time));
3698 /* get time in this segment */
3699 seg_time = offset - segment->time;
3701 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
3702 GST_TIME_ARGS (seg_time));
3704 if (G_UNLIKELY (seg_time > segment->duration)) {
3705 GST_LOG_OBJECT (stream->pad,
3706 "seg_time > segment->duration %" GST_TIME_FORMAT,
3707 GST_TIME_ARGS (segment->duration));
3708 seg_time = segment->duration;
3711 /* qtdemux->segment.stop is in outside-time-realm, whereas
3712 * segment->media_stop is in track-time-realm.
3714 * In order to compare the two, we need to bring segment.stop
3715 * into the track-time-realm */
3717 stop = qtdemux->segment.stop;
3718 if (stop == GST_CLOCK_TIME_NONE)
3719 stop = qtdemux->segment.duration;
3720 if (stop == GST_CLOCK_TIME_NONE)
3721 stop = segment->media_stop;
3724 MIN (segment->media_stop, stop - segment->time + segment->media_start);
3726 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
3727 start = segment->time + seg_time;
3729 stop = start - seg_time + segment->duration;
3730 } else if (qtdemux->segment.rate >= 0) {
3731 start = MIN (segment->media_start + seg_time, stop);
3734 if (segment->media_start >= qtdemux->segment.start) {
3735 time = segment->time;
3737 time = segment->time + (qtdemux->segment.start - segment->media_start);
3740 start = MAX (segment->media_start, qtdemux->segment.start);
3741 stop = MIN (segment->media_start + seg_time, stop);
3744 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
3745 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
3746 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
3748 /* combine global rate with that of the segment */
3749 rate = segment->rate * qtdemux->segment.rate;
3751 /* Copy flags from main segment */
3752 stream->segment.flags = qtdemux->segment.flags;
3754 /* accumulate previous segments */
3755 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
3756 stream->accumulated_base += (stream->segment.stop - stream->segment.start) /
3757 ABS (stream->segment.rate);
3759 /* update the segment values used for clipping */
3760 stream->segment.offset = qtdemux->segment.offset;
3761 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
3762 stream->segment.applied_rate = qtdemux->segment.applied_rate;
3763 stream->segment.rate = rate;
3764 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
3765 stream->cslg_shift);
3766 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
3767 stream->cslg_shift);
3768 stream->segment.time = time;
3769 stream->segment.position = stream->segment.start;
3771 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
3774 /* now prepare and send the segment */
3776 event = gst_event_new_segment (&stream->segment);
3777 if (stream->segment_seqnum) {
3778 gst_event_set_seqnum (event, stream->segment_seqnum);
3780 gst_pad_push_event (stream->pad, event);
3781 /* assume we can send more data now */
3782 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
3783 /* clear to send tags on this pad now */
3784 gst_qtdemux_push_tags (qtdemux, stream);
3787 /* in the fragmented case, we pick a fragment that starts before our
3788 * desired position and rely on downstream to wait for a keyframe
3789 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
3790 * tfra entries tells us which trun/sample the key unit is in, but we don't
3791 * make use of this additional information at the moment) */
3792 if (qtdemux->fragmented) {
3793 stream->to_sample = G_MAXUINT32;
3797 /* and move to the keyframe before the indicated media time of the
3799 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
3800 if (qtdemux->segment.rate >= 0) {
3801 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
3802 stream->to_sample = G_MAXUINT32;
3803 GST_DEBUG_OBJECT (stream->pad,
3804 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
3805 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
3806 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
3808 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
3809 stream->to_sample = index;
3810 GST_DEBUG_OBJECT (stream->pad,
3811 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
3812 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
3813 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
3816 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
3817 "this is an empty segment");
3821 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
3822 * encountered an error and printed a message so we return appropriately */
3826 /* we're at the right spot */
3827 if (index == stream->sample_index) {
3828 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
3832 /* find keyframe of the target index */
3833 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index);
3836 /* indent does stupid stuff with stream->samples[].timestamp */
3838 /* if we move forwards, we don't have to go back to the previous
3839 * keyframe since we already sent that. We can also just jump to
3840 * the keyframe right before the target index if there is one. */
3841 if (index > stream->sample_index) {
3842 /* moving forwards check if we move past a keyframe */
3843 if (kf_index > stream->sample_index) {
3844 GST_DEBUG_OBJECT (stream->pad,
3845 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
3846 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
3847 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
3848 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
3850 GST_DEBUG_OBJECT (stream->pad,
3851 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
3852 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
3853 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
3856 GST_DEBUG_OBJECT (stream->pad,
3857 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
3858 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
3859 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
3860 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
3868 /* prepare to get the current sample of @stream, getting essential values.
3870 * This function will also prepare and send the segment when needed.
3872 * Return FALSE if the stream is EOS.
3877 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
3878 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
3879 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
3880 gboolean * keyframe)
3882 QtDemuxSample *sample;
3883 GstClockTime time_position;
3886 g_return_val_if_fail (stream != NULL, FALSE);
3888 time_position = stream->time_position;
3889 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
3892 seg_idx = stream->segment_index;
3893 if (G_UNLIKELY (seg_idx == -1)) {
3894 /* find segment corresponding to time_position if we are looking
3896 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
3899 /* different segment, activate it, sample_index will be set. */
3900 if (G_UNLIKELY (stream->segment_index != seg_idx))
3901 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
3903 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->segments[stream->
3905 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
3907 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
3908 " prepare empty sample");
3911 *pts = *dts = time_position;
3912 *duration = seg->duration - (time_position - seg->time);
3919 if (stream->sample_index == -1)
3920 stream->sample_index = 0;
3922 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
3923 stream->sample_index, stream->n_samples);
3925 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
3926 if (!qtdemux->fragmented)
3929 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
3933 GST_OBJECT_LOCK (qtdemux);
3934 flow = qtdemux_add_fragmented_samples (qtdemux);
3935 GST_OBJECT_UNLOCK (qtdemux);
3937 if (flow != GST_FLOW_OK)
3940 while (stream->sample_index >= stream->n_samples);
3943 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
3944 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
3945 stream->sample_index);
3949 /* now get the info for the sample we're at */
3950 sample = &stream->samples[stream->sample_index];
3952 *dts = QTSAMPLE_DTS (stream, sample);
3953 *pts = QTSAMPLE_PTS (stream, sample);
3954 *offset = sample->offset;
3955 *size = sample->size;
3956 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
3957 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
3964 stream->time_position = GST_CLOCK_TIME_NONE;
3969 /* move to the next sample in @stream.
3971 * Moves to the next segment when needed.
3974 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
3976 QtDemuxSample *sample;
3977 QtDemuxSegment *segment;
3979 /* get current segment */
3980 segment = &stream->segments[stream->segment_index];
3982 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
3983 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
3987 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
3988 /* Mark the stream as EOS */
3989 GST_DEBUG_OBJECT (qtdemux,
3990 "reached max allowed sample %u, mark EOS", stream->to_sample);
3991 stream->time_position = GST_CLOCK_TIME_NONE;
3995 /* move to next sample */
3996 stream->sample_index++;
3997 stream->offset_in_sample = 0;
3999 /* reached the last sample, we need the next segment */
4000 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
4003 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4004 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4005 stream->sample_index);
4009 /* get next sample */
4010 sample = &stream->samples[stream->sample_index];
4012 /* see if we are past the segment */
4013 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
4016 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
4017 /* inside the segment, update time_position, looks very familiar to
4018 * GStreamer segments, doesn't it? */
4019 stream->time_position =
4020 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
4022 /* not yet in segment, time does not yet increment. This means
4023 * that we are still prerolling keyframes to the decoder so it can
4024 * decode the first sample of the segment. */
4025 stream->time_position = segment->time;
4029 /* move to the next segment */
4032 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
4034 if (stream->segment_index == stream->n_segments - 1) {
4035 /* are we at the end of the last segment, we're EOS */
4036 stream->time_position = GST_CLOCK_TIME_NONE;
4038 /* else we're only at the end of the current segment */
4039 stream->time_position = segment->stop_time;
4041 /* make sure we select a new segment */
4042 stream->segment_index = -1;
4047 gst_qtdemux_sync_streams (GstQTDemux * demux)
4051 if (demux->n_streams <= 1)
4054 for (i = 0; i < demux->n_streams; i++) {
4055 QtDemuxStream *stream;
4056 GstClockTime end_time;
4058 stream = demux->streams[i];
4063 /* TODO advance time on subtitle streams here, if any some day */
4065 /* some clips/trailers may have unbalanced streams at the end,
4066 * so send EOS on shorter stream to prevent stalling others */
4068 /* do not mess with EOS if SEGMENT seeking */
4069 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
4072 if (demux->pullbased) {
4073 /* loop mode is sample time based */
4074 if (!STREAM_IS_EOS (stream))
4077 /* push mode is byte position based */
4078 if (stream->n_samples &&
4079 stream->samples[stream->n_samples - 1].offset >= demux->offset)
4083 if (stream->sent_eos)
4086 /* only act if some gap */
4087 end_time = stream->segments[stream->n_segments - 1].stop_time;
4088 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
4089 ", stream end: %" GST_TIME_FORMAT,
4090 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
4091 if (GST_CLOCK_TIME_IS_VALID (end_time)
4092 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
4093 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
4094 GST_PAD_NAME (stream->pad));
4095 stream->sent_eos = TRUE;
4096 gst_pad_push_event (stream->pad, gst_event_new_eos ());
4101 /* EOS and NOT_LINKED need to be combined. This means that we return:
4103 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
4104 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
4106 static GstFlowReturn
4107 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
4110 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
4113 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
4116 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
4118 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
4122 /* the input buffer metadata must be writable. Returns NULL when the buffer is
4123 * completely clipped
4125 * Should be used only with raw buffers */
4127 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
4130 guint64 start, stop, cstart, cstop, diff;
4131 GstClockTime pts, duration;
4133 gint num_rate, denom_rate;
4138 osize = size = gst_buffer_get_size (buf);
4141 /* depending on the type, setup the clip parameters */
4142 if (stream->subtype == FOURCC_soun) {
4143 frame_size = stream->bytes_per_frame;
4144 num_rate = GST_SECOND;
4145 denom_rate = (gint) stream->rate;
4147 } else if (stream->subtype == FOURCC_vide) {
4149 num_rate = stream->fps_n;
4150 denom_rate = stream->fps_d;
4155 if (frame_size <= 0)
4156 goto bad_frame_size;
4158 /* we can only clip if we have a valid pts */
4159 pts = GST_BUFFER_PTS (buf);
4160 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
4163 duration = GST_BUFFER_DURATION (buf);
4165 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
4167 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
4171 stop = start + duration;
4173 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
4174 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
4177 /* see if some clipping happened */
4178 diff = cstart - start;
4184 /* bring clipped time to samples and to bytes */
4185 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
4188 GST_DEBUG_OBJECT (qtdemux,
4189 "clipping start to %" GST_TIME_FORMAT " %"
4190 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
4196 diff = stop - cstop;
4201 /* bring clipped time to samples and then to bytes */
4202 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
4204 GST_DEBUG_OBJECT (qtdemux,
4205 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
4206 " bytes", GST_TIME_ARGS (cstop), diff);
4211 if (offset != 0 || size != osize)
4212 gst_buffer_resize (buf, offset, size);
4214 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
4215 GST_BUFFER_PTS (buf) = pts;
4216 GST_BUFFER_DURATION (buf) = duration;
4220 /* dropped buffer */
4223 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
4228 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
4233 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
4238 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
4239 gst_buffer_unref (buf);
4244 /* the input buffer metadata must be writable,
4245 * but time/duration etc not yet set and need not be preserved */
4247 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
4254 /* not many cases for now */
4255 if (G_UNLIKELY (stream->fourcc == FOURCC_mp4s)) {
4256 /* send a one time dvd clut event */
4257 if (stream->pending_event && stream->pad)
4258 gst_pad_push_event (stream->pad, stream->pending_event);
4259 stream->pending_event = NULL;
4262 if (G_UNLIKELY (stream->subtype != FOURCC_text
4263 && stream->subtype != FOURCC_sbtl &&
4264 stream->subtype != FOURCC_subp)) {
4268 gst_buffer_map (buf, &map, GST_MAP_READ);
4270 /* empty buffer is sent to terminate previous subtitle */
4271 if (map.size <= 2) {
4272 gst_buffer_unmap (buf, &map);
4273 gst_buffer_unref (buf);
4276 if (stream->subtype == FOURCC_subp) {
4277 /* That's all the processing needed for subpictures */
4278 gst_buffer_unmap (buf, &map);
4282 nsize = GST_READ_UINT16_BE (map.data);
4283 nsize = MIN (nsize, map.size - 2);
4285 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
4288 /* takes care of UTF-8 validation or UTF-16 recognition,
4289 * no other encoding expected */
4290 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
4291 gst_buffer_unmap (buf, &map);
4293 gst_buffer_unref (buf);
4294 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
4296 /* this should not really happen unless the subtitle is corrupted */
4297 gst_buffer_unref (buf);
4301 /* FIXME ? convert optional subsequent style info to markup */
4306 /* Sets a buffer's attributes properly and pushes it downstream.
4307 * Also checks for additional actions and custom processing that may
4308 * need to be done first.
4310 static GstFlowReturn
4311 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
4312 QtDemuxStream * stream, GstBuffer * buf,
4313 GstClockTime dts, GstClockTime pts, GstClockTime duration,
4314 gboolean keyframe, GstClockTime position, guint64 byte_position)
4316 GstFlowReturn ret = GST_FLOW_OK;
4318 /* offset the timestamps according to the edit list */
4320 if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) {
4324 gst_buffer_map (buf, &map, GST_MAP_READ);
4325 url = g_strndup ((gchar *) map.data, map.size);
4326 gst_buffer_unmap (buf, &map);
4327 if (url != NULL && strlen (url) != 0) {
4328 /* we have RTSP redirect now */
4329 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
4330 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
4331 gst_structure_new ("redirect",
4332 "new-location", G_TYPE_STRING, url, NULL)));
4333 qtdemux->posted_redirect = TRUE;
4335 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
4341 /* position reporting */
4342 if (qtdemux->segment.rate >= 0) {
4343 qtdemux->segment.position = position;
4344 gst_qtdemux_sync_streams (qtdemux);
4347 if (G_UNLIKELY (!stream->pad)) {
4348 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
4349 gst_buffer_unref (buf);
4353 /* send out pending buffers */
4354 while (stream->buffers) {
4355 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
4357 if (G_UNLIKELY (stream->discont)) {
4358 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
4359 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
4360 stream->discont = FALSE;
4362 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
4365 gst_pad_push (stream->pad, buffer);
4367 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
4370 /* we're going to modify the metadata */
4371 buf = gst_buffer_make_writable (buf);
4373 if (G_UNLIKELY (stream->need_process))
4374 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
4380 GST_BUFFER_DTS (buf) = dts;
4381 GST_BUFFER_PTS (buf) = pts;
4382 GST_BUFFER_DURATION (buf) = duration;
4383 GST_BUFFER_OFFSET (buf) = -1;
4384 GST_BUFFER_OFFSET_END (buf) = -1;
4386 if (G_UNLIKELY (stream->rgb8_palette))
4387 gst_buffer_append_memory (buf, gst_memory_ref (stream->rgb8_palette));
4389 if (G_UNLIKELY (stream->padding)) {
4390 gst_buffer_resize (buf, stream->padding, -1);
4393 if (G_UNLIKELY (qtdemux->element_index)) {
4394 GstClockTime stream_time;
4397 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
4399 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
4400 GST_LOG_OBJECT (qtdemux,
4401 "adding association %" GST_TIME_FORMAT "-> %"
4402 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
4403 gst_index_add_association (qtdemux->element_index,
4405 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
4406 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
4407 GST_FORMAT_BYTES, byte_position, NULL);
4412 if (stream->need_clip)
4413 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
4415 if (G_UNLIKELY (buf == NULL))
4418 if (G_UNLIKELY (stream->discont)) {
4419 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
4420 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
4421 stream->discont = FALSE;
4423 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
4427 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
4428 stream->on_keyframe = FALSE;
4430 stream->on_keyframe = TRUE;
4434 GST_LOG_OBJECT (qtdemux,
4435 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
4436 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
4437 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
4438 GST_PAD_NAME (stream->pad));
4440 ret = gst_pad_push (stream->pad, buf);
4442 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
4443 /* mark position in stream, we'll need this to know when to send GAP event */
4444 stream->segment.position = pts + duration;
4451 static const QtDemuxRandomAccessEntry *
4452 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4453 GstClockTime pos, gboolean after)
4455 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
4456 guint n_entries = stream->n_ra_entries;
4459 /* we assume the table is sorted */
4460 for (i = 0; i < n_entries; ++i) {
4461 if (entries[i].ts > pos)
4465 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
4466 * probably okay to assume that the index lists the very first fragment */
4473 return &entries[i - 1];
4477 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
4479 const QtDemuxRandomAccessEntry *best_entry = NULL;
4482 GST_OBJECT_LOCK (qtdemux);
4484 g_assert (qtdemux->n_streams > 0);
4486 for (i = 0; i < qtdemux->n_streams; i++) {
4487 const QtDemuxRandomAccessEntry *entry;
4488 QtDemuxStream *stream;
4489 gboolean is_audio_or_video;
4491 stream = qtdemux->streams[i];
4493 g_free (stream->samples);
4494 stream->samples = NULL;
4495 stream->n_samples = 0;
4496 stream->stbl_index = -1; /* no samples have yet been parsed */
4497 stream->sample_index = -1;
4499 if (stream->ra_entries == NULL)
4502 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
4503 is_audio_or_video = TRUE;
4505 is_audio_or_video = FALSE;
4508 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
4509 stream->time_position, !is_audio_or_video);
4511 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
4512 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
4514 stream->pending_seek = entry;
4516 /* decide position to jump to just based on audio/video tracks, not subs */
4517 if (!is_audio_or_video)
4520 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
4524 if (best_entry == NULL) {
4525 GST_OBJECT_UNLOCK (qtdemux);
4529 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
4530 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
4531 GST_TIME_ARGS (qtdemux->streams[0]->time_position),
4532 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
4534 qtdemux->moof_offset = best_entry->moof_offset;
4536 qtdemux_add_fragmented_samples (qtdemux);
4538 GST_OBJECT_UNLOCK (qtdemux);
4542 static GstFlowReturn
4543 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
4545 GstFlowReturn ret = GST_FLOW_OK;
4546 GstBuffer *buf = NULL;
4547 QtDemuxStream *stream;
4548 GstClockTime min_time;
4550 GstClockTime dts = GST_CLOCK_TIME_NONE;
4551 GstClockTime pts = GST_CLOCK_TIME_NONE;
4552 GstClockTime duration = 0;
4553 gboolean keyframe = FALSE;
4554 guint sample_size = 0;
4560 gst_qtdemux_push_pending_newsegment (qtdemux);
4562 if (qtdemux->fragmented_seek_pending) {
4563 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
4564 gst_qtdemux_do_fragmented_seek (qtdemux);
4565 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
4566 qtdemux->fragmented_seek_pending = FALSE;
4569 /* Figure out the next stream sample to output, min_time is expressed in
4570 * global time and runs over the edit list segments. */
4571 min_time = G_MAXUINT64;
4573 for (i = 0; i < qtdemux->n_streams; i++) {
4574 GstClockTime position;
4576 stream = qtdemux->streams[i];
4577 position = stream->time_position;
4579 /* position of -1 is EOS */
4580 if (position != GST_CLOCK_TIME_NONE && position < min_time) {
4581 min_time = position;
4586 if (G_UNLIKELY (index == -1)) {
4587 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
4591 /* check for segment end */
4592 if (G_UNLIKELY (qtdemux->segment.stop != -1
4593 && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
4594 || (qtdemux->segment.rate < 0
4595 && qtdemux->segment.start > min_time))
4596 && qtdemux->streams[index]->on_keyframe)) {
4597 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
4598 qtdemux->streams[index]->time_position = GST_CLOCK_TIME_NONE;
4602 /* gap events for subtitle streams */
4603 for (i = 0; i < qtdemux->n_streams; i++) {
4604 stream = qtdemux->streams[i];
4605 if (stream->pad && (stream->subtype == FOURCC_subp
4606 || stream->subtype == FOURCC_text
4607 || stream->subtype == FOURCC_sbtl)) {
4608 /* send one second gap events until the stream catches up */
4609 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
4610 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
4611 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
4612 stream->segment.position + GST_SECOND < min_time) {
4614 gst_event_new_gap (stream->segment.position, GST_SECOND);
4615 gst_pad_push_event (stream->pad, gap);
4616 stream->segment.position += GST_SECOND;
4621 stream = qtdemux->streams[index];
4622 if (stream->new_caps) {
4623 gst_qtdemux_configure_stream (qtdemux, stream);
4624 qtdemux_do_allocation (qtdemux, stream);
4627 /* fetch info for the current sample of this stream */
4628 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
4629 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
4632 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
4633 if (G_UNLIKELY (qtdemux->
4634 segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
4635 if (stream->subtype == FOURCC_vide && !keyframe) {
4636 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on stream %d", index);
4641 GST_DEBUG_OBJECT (qtdemux,
4642 "pushing from stream %d, empty %d offset %" G_GUINT64_FORMAT
4643 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
4644 ", duration %" GST_TIME_FORMAT, index, empty, offset, sample_size,
4645 GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
4647 if (G_UNLIKELY (empty)) {
4648 /* empty segment, push a gap and move to the next one */
4649 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
4650 stream->segment.position = pts + duration;
4654 /* hmm, empty sample, skip and move to next sample */
4655 if (G_UNLIKELY (sample_size <= 0))
4658 /* last pushed sample was out of boundary, goto next sample */
4659 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
4662 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
4665 GST_DEBUG_OBJECT (qtdemux,
4666 "size %d larger than stream max_buffer_size %d, trimming",
4667 sample_size, stream->max_buffer_size);
4669 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
4672 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
4675 if (stream->use_allocator) {
4676 /* if we have a per-stream allocator, use it */
4677 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
4680 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
4682 if (G_UNLIKELY (ret != GST_FLOW_OK))
4685 if (size != sample_size) {
4686 pts += gst_util_uint64_scale_int (GST_SECOND,
4687 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
4688 dts += gst_util_uint64_scale_int (GST_SECOND,
4689 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
4690 duration = gst_util_uint64_scale_int (GST_SECOND,
4691 size / stream->bytes_per_frame, stream->timescale);
4694 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
4695 dts, pts, duration, keyframe, min_time, offset);
4697 if (size != sample_size) {
4698 QtDemuxSample *sample = &stream->samples[stream->sample_index];
4699 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
4701 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
4702 sample->timestamp + stream->offset_in_sample / stream->bytes_per_frame);
4703 if (time_position >= segment->media_start) {
4704 /* inside the segment, update time_position, looks very familiar to
4705 * GStreamer segments, doesn't it? */
4706 stream->time_position = (time_position - segment->media_start) +
4709 /* not yet in segment, time does not yet increment. This means
4710 * that we are still prerolling keyframes to the decoder so it can
4711 * decode the first sample of the segment. */
4712 stream->time_position = segment->time;
4717 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
4718 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
4719 * we have no more data for the pad to push */
4720 if (ret == GST_FLOW_EOS)
4723 stream->offset_in_sample += size;
4724 if (stream->offset_in_sample >= sample_size) {
4725 gst_qtdemux_advance_sample (qtdemux, stream);
4730 gst_qtdemux_advance_sample (qtdemux, stream);
4738 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
4744 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
4745 /* EOS will be raised if all are EOS */
4752 gst_qtdemux_loop (GstPad * pad)
4754 GstQTDemux *qtdemux;
4758 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
4760 cur_offset = qtdemux->offset;
4761 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %d",
4762 cur_offset, qtdemux->state);
4764 switch (qtdemux->state) {
4765 case QTDEMUX_STATE_INITIAL:
4766 case QTDEMUX_STATE_HEADER:
4767 ret = gst_qtdemux_loop_state_header (qtdemux);
4769 case QTDEMUX_STATE_MOVIE:
4770 ret = gst_qtdemux_loop_state_movie (qtdemux);
4771 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
4772 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
4780 /* if something went wrong, pause */
4781 if (ret != GST_FLOW_OK)
4785 gst_object_unref (qtdemux);
4791 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
4792 (NULL), ("streaming stopped, invalid state"));
4793 gst_pad_pause_task (pad);
4794 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
4799 const gchar *reason = gst_flow_get_name (ret);
4801 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
4803 gst_pad_pause_task (pad);
4805 /* fatal errors need special actions */
4807 if (ret == GST_FLOW_EOS) {
4808 if (qtdemux->n_streams == 0) {
4809 /* we have no streams, post an error */
4810 gst_qtdemux_post_no_playable_stream_error (qtdemux);
4812 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
4815 if ((stop = qtdemux->segment.stop) == -1)
4816 stop = qtdemux->segment.duration;
4818 if (qtdemux->segment.rate >= 0) {
4819 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
4820 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
4821 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
4822 GST_FORMAT_TIME, stop));
4823 gst_qtdemux_push_event (qtdemux,
4824 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
4826 /* For Reverse Playback */
4827 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
4828 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
4829 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
4830 GST_FORMAT_TIME, qtdemux->segment.start));
4831 gst_qtdemux_push_event (qtdemux,
4832 gst_event_new_segment_done (GST_FORMAT_TIME,
4833 qtdemux->segment.start));
4836 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
4837 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
4839 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
4840 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
4841 (NULL), ("streaming stopped, reason %s", reason));
4842 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
4851 * Returns if there are samples to be played.
4854 has_next_entry (GstQTDemux * demux)
4856 QtDemuxStream *stream;
4859 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
4861 for (i = 0; i < demux->n_streams; i++) {
4862 stream = demux->streams[i];
4864 if (stream->sample_index == -1) {
4865 stream->sample_index = 0;
4866 stream->offset_in_sample = 0;
4869 if (stream->sample_index >= stream->n_samples) {
4870 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
4873 GST_DEBUG_OBJECT (demux, "Found a sample");
4877 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
4884 * Returns the size of the first entry at the current offset.
4885 * If -1, there are none (which means EOS or empty file).
4888 next_entry_size (GstQTDemux * demux)
4890 QtDemuxStream *stream;
4893 guint64 smalloffs = (guint64) - 1;
4894 QtDemuxSample *sample;
4896 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
4899 for (i = 0; i < demux->n_streams; i++) {
4900 stream = demux->streams[i];
4902 if (stream->sample_index == -1) {
4903 stream->sample_index = 0;
4904 stream->offset_in_sample = 0;
4907 if (stream->sample_index >= stream->n_samples) {
4908 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
4912 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
4913 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
4914 stream->sample_index);
4918 sample = &stream->samples[stream->sample_index];
4920 GST_LOG_OBJECT (demux,
4921 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
4922 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
4923 sample->offset, sample->size);
4925 if (((smalloffs == -1)
4926 || (sample->offset < smalloffs)) && (sample->size)) {
4928 smalloffs = sample->offset;
4932 GST_LOG_OBJECT (demux,
4933 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
4934 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
4939 stream = demux->streams[smallidx];
4940 sample = &stream->samples[stream->sample_index];
4942 if (sample->offset >= demux->offset) {
4943 demux->todrop = sample->offset - demux->offset;
4944 return sample->size + demux->todrop;
4947 GST_DEBUG_OBJECT (demux,
4948 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
4953 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
4955 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
4957 gst_element_post_message (GST_ELEMENT_CAST (demux),
4958 gst_message_new_element (GST_OBJECT_CAST (demux),
4959 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
4963 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
4968 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
4971 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
4972 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
4973 GST_SEEK_TYPE_NONE, -1);
4975 res = gst_pad_push_event (demux->sinkpad, event);
4980 /* check for seekable upstream, above and beyond a mere query */
4982 gst_qtdemux_check_seekability (GstQTDemux * demux)
4985 gboolean seekable = FALSE;
4986 gint64 start = -1, stop = -1;
4988 if (demux->upstream_size)
4991 query = gst_query_new_seeking (GST_FORMAT_BYTES);
4992 if (!gst_pad_peer_query (demux->sinkpad, query)) {
4993 GST_DEBUG_OBJECT (demux, "seeking query failed");
4997 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
4999 /* try harder to query upstream size if we didn't get it the first time */
5000 if (seekable && stop == -1) {
5001 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
5002 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
5005 /* if upstream doesn't know the size, it's likely that it's not seekable in
5006 * practice even if it technically may be seekable */
5007 if (seekable && (start != 0 || stop <= start)) {
5008 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
5013 gst_query_unref (query);
5015 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
5016 G_GUINT64_FORMAT ")", seekable, start, stop);
5017 demux->upstream_seekable = seekable;
5018 demux->upstream_size = seekable ? stop : -1;
5022 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
5024 g_return_if_fail (bytes <= demux->todrop);
5026 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
5027 gst_adapter_flush (demux->adapter, bytes);
5028 demux->neededbytes -= bytes;
5029 demux->offset += bytes;
5030 demux->todrop -= bytes;
5033 static GstFlowReturn
5034 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
5038 demux = GST_QTDEMUX (parent);
5040 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
5043 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
5045 for (i = 0; i < demux->n_streams; i++) {
5046 demux->streams[i]->discont = TRUE;
5049 /* Reverse fragmented playback, need to flush all we have before
5050 * consuming a new fragment.
5051 * The samples array have the timestamps calculated by accumulating the
5052 * durations but this won't work for reverse playback of fragments as
5053 * the timestamps of a subsequent fragment should be smaller than the
5054 * previously received one. */
5055 if (demux->fragmented && demux->segment.rate < 0) {
5056 gst_qtdemux_process_adapter (demux, TRUE);
5057 for (i = 0; i < demux->n_streams; i++)
5058 gst_qtdemux_stream_flush_samples_data (demux, demux->streams[i]);
5062 gst_adapter_push (demux->adapter, inbuf);
5064 GST_DEBUG_OBJECT (demux,
5065 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
5066 demux->neededbytes, gst_adapter_available (demux->adapter));
5068 return gst_qtdemux_process_adapter (demux, FALSE);
5071 static GstFlowReturn
5072 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
5074 GstFlowReturn ret = GST_FLOW_OK;
5076 /* we never really mean to buffer that much */
5077 if (demux->neededbytes == -1) {
5081 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
5082 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
5084 GST_DEBUG_OBJECT (demux,
5085 "state:%d , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT,
5086 demux->state, demux->neededbytes, demux->offset);
5088 switch (demux->state) {
5089 case QTDEMUX_STATE_INITIAL:{
5094 gst_qtdemux_check_seekability (demux);
5096 data = gst_adapter_map (demux->adapter, demux->neededbytes);
5098 /* get fourcc/length, set neededbytes */
5099 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
5101 gst_adapter_unmap (demux->adapter);
5103 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
5104 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
5106 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
5107 (_("This file is invalid and cannot be played.")),
5108 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
5109 GST_FOURCC_ARGS (fourcc)));
5110 ret = GST_FLOW_ERROR;
5113 if (fourcc == FOURCC_mdat) {
5114 gint next_entry = next_entry_size (demux);
5115 if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
5116 /* we have the headers, start playback */
5117 demux->state = QTDEMUX_STATE_MOVIE;
5118 demux->neededbytes = next_entry;
5119 demux->mdatleft = size;
5121 /* no headers yet, try to get them */
5124 guint64 old, target;
5127 old = demux->offset;
5128 target = old + size;
5130 /* try to jump over the atom with a seek */
5131 /* only bother if it seems worth doing so,
5132 * and avoids possible upstream/server problems */
5133 if (demux->upstream_seekable &&
5134 demux->upstream_size > 4 * (1 << 20)) {
5135 res = qtdemux_seek_offset (demux, target);
5137 GST_DEBUG_OBJECT (demux, "skipping seek");
5142 GST_DEBUG_OBJECT (demux, "seek success");
5143 /* remember the offset fo the first mdat so we can seek back to it
5144 * after we have the headers */
5145 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
5146 demux->first_mdat = old;
5147 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
5150 /* seek worked, continue reading */
5151 demux->offset = target;
5152 demux->neededbytes = 16;
5153 demux->state = QTDEMUX_STATE_INITIAL;
5155 /* seek failed, need to buffer */
5156 demux->offset = old;
5157 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
5158 /* there may be multiple mdat (or alike) buffers */
5160 if (demux->mdatbuffer)
5161 bs = gst_buffer_get_size (demux->mdatbuffer);
5164 if (size + bs > 10 * (1 << 20))
5166 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
5167 demux->neededbytes = size;
5168 if (!demux->mdatbuffer)
5169 demux->mdatoffset = demux->offset;
5172 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
5173 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
5174 (_("This file is invalid and cannot be played.")),
5175 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
5176 GST_FOURCC_ARGS (fourcc), size));
5177 ret = GST_FLOW_ERROR;
5180 /* this means we already started buffering and still no moov header,
5181 * let's continue buffering everything till we get moov */
5182 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
5183 || fourcc == FOURCC_moof))
5185 demux->neededbytes = size;
5186 demux->state = QTDEMUX_STATE_HEADER;
5190 case QTDEMUX_STATE_HEADER:{
5194 GST_DEBUG_OBJECT (demux, "In header");
5196 data = gst_adapter_map (demux->adapter, demux->neededbytes);
5198 /* parse the header */
5199 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
5201 if (fourcc == FOURCC_moov) {
5202 /* in usual fragmented setup we could try to scan for more
5203 * and end up at the the moov (after mdat) again */
5204 if (demux->got_moov && demux->n_streams > 0 &&
5206 || demux->last_moov_offset == demux->offset)) {
5207 GST_DEBUG_OBJECT (demux,
5208 "Skipping moov atom as we have (this) one already");
5210 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
5212 if (demux->got_moov && demux->fragmented) {
5213 GST_DEBUG_OBJECT (demux,
5214 "Got a second moov, clean up data from old one");
5215 if (demux->moov_node)
5216 g_node_destroy (demux->moov_node);
5217 demux->moov_node = NULL;
5218 demux->moov_node_compressed = NULL;
5220 /* prepare newsegment to send when streaming actually starts */
5221 if (!demux->pending_newsegment)
5222 demux->pending_newsegment =
5223 gst_event_new_segment (&demux->segment);
5226 demux->last_moov_offset = demux->offset;
5228 qtdemux_parse_moov (demux, data, demux->neededbytes);
5229 qtdemux_node_dump (demux, demux->moov_node);
5230 qtdemux_parse_tree (demux);
5231 qtdemux_prepare_streams (demux);
5232 if (!demux->got_moov)
5233 qtdemux_expose_streams (demux);
5237 for (n = 0; n < demux->n_streams; n++) {
5238 QtDemuxStream *stream = demux->streams[n];
5240 gst_qtdemux_configure_stream (demux, stream);
5244 demux->got_moov = TRUE;
5246 g_node_destroy (demux->moov_node);
5247 demux->moov_node = NULL;
5248 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
5250 } else if (fourcc == FOURCC_moof) {
5251 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
5253 GstClockTime prev_pts;
5254 guint64 prev_offset;
5256 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
5259 * The timestamp of the moof buffer is relevant as some scenarios
5260 * won't have the initial timestamp in the atoms. Whenever a new
5261 * buffer has started, we get that buffer's PTS and use it as a base
5262 * timestamp for the trun entries.
5264 * To keep track of the current buffer timestamp and starting point
5265 * we use gst_adapter_prev_pts that gives us the PTS and the distance
5266 * from the beggining of the buffer, with the distance and demux->offset
5267 * we know if it is still the same buffer or not.
5269 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
5270 prev_offset = demux->offset - dist;
5271 if (demux->fragment_start_offset == -1
5272 || prev_offset > demux->fragment_start_offset) {
5273 demux->fragment_start_offset = prev_offset;
5274 demux->fragment_start = prev_pts;
5275 GST_DEBUG_OBJECT (demux,
5276 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
5277 GST_TIME_FORMAT, demux->fragment_start_offset,
5278 GST_TIME_ARGS (demux->fragment_start));
5281 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
5282 demux->offset, NULL)) {
5283 gst_adapter_unmap (demux->adapter);
5284 ret = GST_FLOW_ERROR;
5287 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
5288 if (demux->mss_mode && !demux->exposed) {
5289 if (!demux->pending_newsegment) {
5291 gst_segment_init (&segment, GST_FORMAT_TIME);
5292 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
5293 demux->pending_newsegment = gst_event_new_segment (&segment);
5295 qtdemux_expose_streams (demux);
5298 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
5300 } else if (fourcc == FOURCC_ftyp) {
5301 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
5302 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
5303 } else if (fourcc == FOURCC_uuid) {
5304 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
5305 qtdemux_parse_uuid (demux, data, demux->neededbytes);
5306 } else if (fourcc == FOURCC_sidx) {
5307 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
5308 qtdemux_parse_sidx (demux, data, demux->neededbytes);
5310 GST_WARNING_OBJECT (demux,
5311 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
5312 GST_FOURCC_ARGS (fourcc));
5313 /* Let's jump that one and go back to initial state */
5315 gst_adapter_unmap (demux->adapter);
5318 if (demux->mdatbuffer && demux->n_streams) {
5319 gsize remaining_data_size = 0;
5321 /* the mdat was before the header */
5322 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
5323 demux->n_streams, demux->mdatbuffer);
5324 /* restore our adapter/offset view of things with upstream;
5325 * put preceding buffered data ahead of current moov data.
5326 * This should also handle evil mdat, moov, mdat cases and alike */
5327 gst_adapter_flush (demux->adapter, demux->neededbytes);
5329 /* Store any remaining data after the mdat for later usage */
5330 remaining_data_size = gst_adapter_available (demux->adapter);
5331 if (remaining_data_size > 0) {
5332 g_assert (demux->restoredata_buffer == NULL);
5333 demux->restoredata_buffer =
5334 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
5335 demux->restoredata_offset = demux->offset + demux->neededbytes;
5336 GST_DEBUG_OBJECT (demux,
5337 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
5338 G_GUINT64_FORMAT, remaining_data_size,
5339 demux->restoredata_offset);
5342 gst_adapter_push (demux->adapter, demux->mdatbuffer);
5343 demux->mdatbuffer = NULL;
5344 demux->offset = demux->mdatoffset;
5345 demux->neededbytes = next_entry_size (demux);
5346 demux->state = QTDEMUX_STATE_MOVIE;
5347 demux->mdatleft = gst_adapter_available (demux->adapter);
5349 GST_DEBUG_OBJECT (demux, "Carrying on normally");
5350 gst_adapter_flush (demux->adapter, demux->neededbytes);
5352 /* only go back to the mdat if there are samples to play */
5353 if (demux->got_moov && demux->first_mdat != -1
5354 && has_next_entry (demux)) {
5357 /* we need to seek back */
5358 res = qtdemux_seek_offset (demux, demux->first_mdat);
5360 demux->offset = demux->first_mdat;
5362 GST_DEBUG_OBJECT (demux, "Seek back failed");
5365 demux->offset += demux->neededbytes;
5367 demux->neededbytes = 16;
5368 demux->state = QTDEMUX_STATE_INITIAL;
5373 case QTDEMUX_STATE_BUFFER_MDAT:{
5377 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
5379 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
5380 gst_buffer_extract (buf, 0, fourcc, 4);
5381 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
5382 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
5383 if (demux->mdatbuffer)
5384 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
5386 demux->mdatbuffer = buf;
5387 demux->offset += demux->neededbytes;
5388 demux->neededbytes = 16;
5389 demux->state = QTDEMUX_STATE_INITIAL;
5390 gst_qtdemux_post_progress (demux, 1, 1);
5394 case QTDEMUX_STATE_MOVIE:{
5395 QtDemuxStream *stream = NULL;
5396 QtDemuxSample *sample;
5398 GstClockTime dts, pts, duration;
5401 GST_DEBUG_OBJECT (demux,
5402 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
5404 if (demux->fragmented) {
5405 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
5407 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
5408 /* if needed data starts within this atom,
5409 * then it should not exceed this atom */
5410 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
5411 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
5412 (_("This file is invalid and cannot be played.")),
5413 ("sample data crosses atom boundary"));
5414 ret = GST_FLOW_ERROR;
5417 demux->mdatleft -= demux->neededbytes;
5419 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
5420 /* so we are dropping more than left in this atom */
5421 gst_qtdemux_drop_data (demux, demux->mdatleft);
5422 demux->mdatleft = 0;
5424 /* need to resume atom parsing so we do not miss any other pieces */
5425 demux->state = QTDEMUX_STATE_INITIAL;
5426 demux->neededbytes = 16;
5428 /* check if there was any stored post mdat data from previous buffers */
5429 if (demux->restoredata_buffer) {
5430 g_assert (gst_adapter_available (demux->adapter) == 0);
5432 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
5433 demux->restoredata_buffer = NULL;
5434 demux->offset = demux->restoredata_offset;
5441 if (demux->todrop) {
5442 gst_qtdemux_drop_data (demux, demux->todrop);
5446 /* initial newsegment sent here after having added pads,
5447 * possible others in sink_event */
5448 if (G_UNLIKELY (demux->pending_newsegment)) {
5449 gst_qtdemux_push_pending_newsegment (demux);
5450 /* clear to send tags on all streams */
5451 for (i = 0; i < demux->n_streams; i++) {
5452 stream = demux->streams[i];
5453 gst_qtdemux_push_tags (demux, stream);
5454 if (stream->sparse) {
5455 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
5456 gst_pad_push_event (stream->pad,
5457 gst_event_new_gap (stream->segment.position,
5458 GST_CLOCK_TIME_NONE));
5463 /* Figure out which stream this packet belongs to */
5464 for (i = 0; i < demux->n_streams; i++) {
5465 stream = demux->streams[i];
5466 if (stream->sample_index >= stream->n_samples)
5468 GST_LOG_OBJECT (demux,
5469 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
5470 " / size:%d)", i, stream->sample_index,
5471 stream->samples[stream->sample_index].offset,
5472 stream->samples[stream->sample_index].size);
5474 if (stream->samples[stream->sample_index].offset == demux->offset)
5478 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
5479 goto unknown_stream;
5481 if (stream->new_caps) {
5482 gst_qtdemux_configure_stream (demux, stream);
5485 /* Put data in a buffer, set timestamps, caps, ... */
5486 sample = &stream->samples[stream->sample_index];
5488 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
5489 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
5490 GST_FOURCC_ARGS (stream->fourcc));
5492 dts = QTSAMPLE_DTS (stream, sample);
5493 pts = QTSAMPLE_PTS (stream, sample);
5494 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
5495 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5497 /* check for segment end */
5498 if (G_UNLIKELY (demux->segment.stop != -1
5499 && demux->segment.stop <= pts && stream->on_keyframe)) {
5500 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
5501 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
5503 /* skip this data, stream is EOS */
5504 gst_adapter_flush (demux->adapter, demux->neededbytes);
5506 /* check if all streams are eos */
5508 for (i = 0; i < demux->n_streams; i++) {
5509 if (!STREAM_IS_EOS (demux->streams[i])) {
5515 if (ret == GST_FLOW_EOS) {
5516 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
5523 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
5525 /* FIXME: should either be an assert or a plain check */
5526 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
5528 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
5529 dts, pts, duration, keyframe, dts, demux->offset);
5533 ret = gst_qtdemux_combine_flows (demux, stream, ret);
5535 /* skip this data, stream is EOS */
5536 gst_adapter_flush (demux->adapter, demux->neededbytes);
5539 stream->sample_index++;
5540 stream->offset_in_sample = 0;
5542 /* update current offset and figure out size of next buffer */
5543 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
5544 demux->offset, demux->neededbytes);
5545 demux->offset += demux->neededbytes;
5546 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
5549 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
5550 if (demux->fragmented) {
5551 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
5552 /* there may be more to follow, only finish this atom */
5553 demux->todrop = demux->mdatleft;
5554 demux->neededbytes = demux->todrop;
5566 /* when buffering movie data, at least show user something is happening */
5567 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
5568 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
5569 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
5570 demux->neededbytes);
5579 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
5580 ret = GST_FLOW_ERROR;
5585 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
5591 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
5592 (NULL), ("qtdemuxer invalid state %d", demux->state));
5593 ret = GST_FLOW_ERROR;
5598 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
5599 (NULL), ("no 'moov' atom within the first 10 MB"));
5600 ret = GST_FLOW_ERROR;
5606 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
5611 query = gst_query_new_scheduling ();
5613 if (!gst_pad_peer_query (sinkpad, query)) {
5614 gst_query_unref (query);
5618 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
5619 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
5620 gst_query_unref (query);
5625 GST_DEBUG_OBJECT (sinkpad, "activating pull");
5626 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
5630 GST_DEBUG_OBJECT (sinkpad, "activating push");
5631 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
5636 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
5637 GstPadMode mode, gboolean active)
5640 GstQTDemux *demux = GST_QTDEMUX (parent);
5643 case GST_PAD_MODE_PUSH:
5644 demux->pullbased = FALSE;
5647 case GST_PAD_MODE_PULL:
5649 demux->pullbased = TRUE;
5650 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
5653 res = gst_pad_stop_task (sinkpad);
5665 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
5667 return g_malloc (items * size);
5671 qtdemux_zfree (void *opaque, void *addr)
5677 qtdemux_inflate (void *z_buffer, guint z_length, guint length)
5683 z = g_new0 (z_stream, 1);
5684 z->zalloc = qtdemux_zalloc;
5685 z->zfree = qtdemux_zfree;
5688 z->next_in = z_buffer;
5689 z->avail_in = z_length;
5691 buffer = (guint8 *) g_malloc (length);
5692 ret = inflateInit (z);
5693 while (z->avail_in > 0) {
5694 if (z->avail_out == 0) {
5696 buffer = (guint8 *) g_realloc (buffer, length);
5697 z->next_out = buffer + z->total_out;
5698 z->avail_out = 1024;
5700 ret = inflate (z, Z_SYNC_FLUSH);
5704 if (ret != Z_STREAM_END) {
5705 g_warning ("inflate() returned %d", ret);
5711 #endif /* HAVE_ZLIB */
5714 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
5718 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
5720 /* counts as header data */
5721 qtdemux->header_size += length;
5723 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
5724 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
5726 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
5732 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
5733 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
5734 if (dcom == NULL || cmvd == NULL)
5735 goto invalid_compression;
5737 method = QT_FOURCC ((guint8 *) dcom->data + 8);
5740 case GST_MAKE_FOURCC ('z', 'l', 'i', 'b'):{
5741 guint uncompressed_length;
5742 guint compressed_length;
5745 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
5746 compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12;
5747 GST_LOG ("length = %u", uncompressed_length);
5750 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
5751 compressed_length, uncompressed_length);
5753 qtdemux->moov_node_compressed = qtdemux->moov_node;
5754 qtdemux->moov_node = g_node_new (buf);
5756 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
5757 uncompressed_length);
5760 #endif /* HAVE_ZLIB */
5762 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
5763 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
5770 invalid_compression:
5772 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
5778 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
5781 while (G_UNLIKELY (buf < end)) {
5785 if (G_UNLIKELY (buf + 4 > end)) {
5786 GST_LOG_OBJECT (qtdemux, "buffer overrun");
5789 len = QT_UINT32 (buf);
5790 if (G_UNLIKELY (len == 0)) {
5791 GST_LOG_OBJECT (qtdemux, "empty container");
5794 if (G_UNLIKELY (len < 8)) {
5795 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
5798 if (G_UNLIKELY (len > (end - buf))) {
5799 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
5800 (gint) (end - buf));
5804 child = g_node_new ((guint8 *) buf);
5805 g_node_append (node, child);
5806 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
5807 qtdemux_parse_node (qtdemux, child, buf, len);
5815 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
5818 int len = QT_UINT32 (xdxt->data);
5819 guint8 *buf = xdxt->data;
5820 guint8 *end = buf + len;
5823 /* skip size and type */
5831 size = QT_UINT32 (buf);
5832 type = QT_FOURCC (buf + 4);
5834 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
5836 if (buf + size > end || size <= 0)
5842 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
5843 GST_FOURCC_ARGS (type));
5847 buffer = gst_buffer_new_and_alloc (size);
5848 gst_buffer_fill (buffer, 0, buf, size);
5849 stream->buffers = g_slist_append (stream->buffers, buffer);
5850 GST_LOG_OBJECT (qtdemux, "parsing theora header");
5853 buffer = gst_buffer_new_and_alloc (size);
5854 gst_buffer_fill (buffer, 0, buf, size);
5855 stream->buffers = g_slist_append (stream->buffers, buffer);
5856 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
5859 buffer = gst_buffer_new_and_alloc (size);
5860 gst_buffer_fill (buffer, 0, buf, size);
5861 stream->buffers = g_slist_append (stream->buffers, buffer);
5862 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
5865 GST_WARNING_OBJECT (qtdemux,
5866 "unknown theora cookie %" GST_FOURCC_FORMAT,
5867 GST_FOURCC_ARGS (type));
5876 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
5880 guint32 node_length = 0;
5881 const QtNodeType *type;
5884 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
5886 if (G_UNLIKELY (length < 8))
5887 goto not_enough_data;
5889 node_length = QT_UINT32 (buffer);
5890 fourcc = QT_FOURCC (buffer + 4);
5892 /* ignore empty nodes */
5893 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
5896 type = qtdemux_type_get (fourcc);
5898 end = buffer + length;
5900 GST_LOG_OBJECT (qtdemux,
5901 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
5902 GST_FOURCC_ARGS (fourcc), node_length, type->name);
5904 if (node_length > length)
5905 goto broken_atom_size;
5907 if (type->flags & QT_FLAG_CONTAINER) {
5908 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
5913 if (node_length < 20) {
5914 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
5917 GST_DEBUG_OBJECT (qtdemux,
5918 "parsing stsd (sample table, sample description) atom");
5919 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
5920 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
5930 /* also read alac (or whatever) in stead of mp4a in the following,
5931 * since a similar layout is used in other cases as well */
5932 if (fourcc == FOURCC_mp4a)
5937 /* There are two things we might encounter here: a true mp4a atom, and
5938 an mp4a entry in an stsd atom. The latter is what we're interested
5939 in, and it looks like an atom, but isn't really one. The true mp4a
5940 atom is short, so we detect it based on length here. */
5941 if (length < min_size) {
5942 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
5943 GST_FOURCC_ARGS (fourcc));
5947 /* 'version' here is the sound sample description version. Types 0 and
5948 1 are documented in the QTFF reference, but type 2 is not: it's
5949 described in Apple header files instead (struct SoundDescriptionV2
5951 version = QT_UINT16 (buffer + 16);
5953 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
5954 GST_FOURCC_ARGS (fourcc), version);
5956 /* parse any esds descriptors */
5968 GST_WARNING_OBJECT (qtdemux,
5969 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
5970 GST_FOURCC_ARGS (fourcc), version);
5975 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
5992 /* codec_data is contained inside these atoms, which all have
5993 * the same format. */
5995 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
5996 GST_FOURCC_ARGS (fourcc));
5997 version = QT_UINT32 (buffer + 16);
5998 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
5999 if (1 || version == 0x00000000) {
6000 buf = buffer + 0x32;
6002 /* FIXME Quicktime uses PASCAL string while
6003 * the iso format uses C strings. Check the file
6004 * type before attempting to parse the string here. */
6005 tlen = QT_UINT8 (buf);
6006 GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
6008 GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
6009 /* the string has a reserved space of 32 bytes so skip
6010 * the remaining 31 */
6012 buf += 4; /* and 4 bytes reserved */
6014 GST_MEMDUMP_OBJECT (qtdemux, "mp4v", buf, end - buf);
6016 qtdemux_parse_container (qtdemux, node, buf, end);
6022 GST_MEMDUMP_OBJECT (qtdemux, "H264", buffer, end - buffer);
6023 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6028 GST_MEMDUMP_OBJECT (qtdemux, "avc1", buffer, end - buffer);
6029 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6034 GST_MEMDUMP_OBJECT (qtdemux, "avc3", buffer, end - buffer);
6035 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6040 GST_MEMDUMP_OBJECT (qtdemux, "H265", buffer, end - buffer);
6041 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6046 GST_MEMDUMP_OBJECT (qtdemux, "hvc1", buffer, end - buffer);
6047 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6052 GST_MEMDUMP_OBJECT (qtdemux, "hev1", buffer, end - buffer);
6053 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6058 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
6063 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
6064 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
6069 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
6070 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
6071 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
6079 version = QT_UINT32 (buffer + 12);
6080 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
6087 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
6092 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
6097 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
6102 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
6106 if (!strcmp (type->name, "unknown"))
6107 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
6111 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
6112 GST_FOURCC_ARGS (fourcc));
6118 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
6119 (_("This file is corrupt and cannot be played.")),
6120 ("Not enough data for an atom header, got only %u bytes", length));
6125 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
6126 (_("This file is corrupt and cannot be played.")),
6127 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
6128 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
6135 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
6139 guint32 child_fourcc;
6141 for (child = g_node_first_child (node); child;
6142 child = g_node_next_sibling (child)) {
6143 buffer = (guint8 *) child->data;
6145 child_fourcc = QT_FOURCC (buffer + 4);
6147 if (G_UNLIKELY (child_fourcc == fourcc)) {
6155 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
6156 GstByteReader * parser)
6160 guint32 child_fourcc, child_len;
6162 for (child = g_node_first_child (node); child;
6163 child = g_node_next_sibling (child)) {
6164 buffer = (guint8 *) child->data;
6166 child_len = QT_UINT32 (buffer);
6167 child_fourcc = QT_FOURCC (buffer + 4);
6169 if (G_UNLIKELY (child_fourcc == fourcc)) {
6170 if (G_UNLIKELY (child_len < (4 + 4)))
6172 /* FIXME: must verify if atom length < parent atom length */
6173 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
6181 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
6182 GstByteReader * parser)
6186 guint32 child_fourcc, child_len;
6188 for (child = g_node_next_sibling (node); child;
6189 child = g_node_next_sibling (child)) {
6190 buffer = (guint8 *) child->data;
6192 child_fourcc = QT_FOURCC (buffer + 4);
6194 if (child_fourcc == fourcc) {
6196 child_len = QT_UINT32 (buffer);
6197 if (G_UNLIKELY (child_len < (4 + 4)))
6199 /* FIXME: must verify if atom length < parent atom length */
6200 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
6209 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
6211 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
6215 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
6217 /* FIXME: This can only reliably work if demuxers have a
6218 * separate streaming thread per srcpad. This should be
6219 * done in a demuxer base class, which integrates parts
6222 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
6227 query = gst_query_new_allocation (stream->caps, FALSE);
6229 if (!gst_pad_peer_query (stream->pad, query)) {
6230 /* not a problem, just debug a little */
6231 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
6234 if (stream->allocator)
6235 gst_object_unref (stream->allocator);
6237 if (gst_query_get_n_allocation_params (query) > 0) {
6238 /* try the allocator */
6239 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
6241 stream->use_allocator = TRUE;
6243 stream->allocator = NULL;
6244 gst_allocation_params_init (&stream->params);
6245 stream->use_allocator = FALSE;
6247 gst_query_unref (query);
6252 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
6254 if (stream->subtype == FOURCC_vide) {
6255 /* fps is calculated base on the duration of the average framerate since
6256 * qt does not have a fixed framerate. */
6257 if ((stream->n_samples == 1) && (stream->first_duration == 0)) {
6262 if (stream->duration == 0 || stream->n_samples < 2) {
6263 stream->fps_n = stream->timescale;
6266 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
6267 /* stream->duration is guint64, timescale, n_samples are guint32 */
6268 GstClockTime avg_duration =
6269 gst_util_uint64_scale_round (stream->duration -
6270 stream->first_duration, GST_SECOND,
6271 (guint64) (stream->timescale) * (stream->n_samples - 1));
6273 GST_LOG_OBJECT (qtdemux,
6274 "Calculating avg sample duration based on stream duration %"
6276 " minus first sample %u, leaving %d samples gives %"
6277 GST_TIME_FORMAT, stream->duration, stream->first_duration,
6278 stream->n_samples - 1, GST_TIME_ARGS (avg_duration));
6280 gst_video_guess_framerate (avg_duration, &stream->fps_n,
6283 GST_DEBUG_OBJECT (qtdemux,
6284 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
6285 stream->timescale, stream->fps_n, stream->fps_d);
6289 stream->caps = gst_caps_make_writable (stream->caps);
6291 gst_caps_set_simple (stream->caps,
6292 "width", G_TYPE_INT, stream->width,
6293 "height", G_TYPE_INT, stream->height,
6294 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
6296 /* calculate pixel-aspect-ratio using display width and height */
6297 GST_DEBUG_OBJECT (qtdemux,
6298 "video size %dx%d, target display size %dx%d", stream->width,
6299 stream->height, stream->display_width, stream->display_height);
6300 /* qt file might have pasp atom */
6301 if (stream->par_w > 0 && stream->par_h > 0) {
6302 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
6303 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
6304 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
6305 } else if (stream->display_width > 0 && stream->display_height > 0 &&
6306 stream->width > 0 && stream->height > 0) {
6309 /* calculate the pixel aspect ratio using the display and pixel w/h */
6310 n = stream->display_width * stream->height;
6311 d = stream->display_height * stream->width;
6314 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
6317 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
6318 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
6321 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
6322 guint par_w = 1, par_h = 1;
6324 if (stream->par_w > 0 && stream->par_h > 0) {
6325 par_w = stream->par_w;
6326 par_h = stream->par_h;
6329 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
6330 stream->width, stream->height, par_w, par_h)) {
6331 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
6334 gst_caps_set_simple (stream->caps,
6335 "multiview-mode", G_TYPE_STRING,
6336 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
6337 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
6338 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
6343 else if (stream->subtype == FOURCC_soun) {
6345 stream->caps = gst_caps_make_writable (stream->caps);
6346 if (stream->rate > 0)
6347 gst_caps_set_simple (stream->caps,
6348 "rate", G_TYPE_INT, (int) stream->rate, NULL);
6349 if (stream->n_channels > 0)
6350 gst_caps_set_simple (stream->caps,
6351 "channels", G_TYPE_INT, stream->n_channels, NULL);
6352 if (stream->n_channels > 2) {
6353 /* FIXME: Need to parse the 'chan' atom to get channel layouts
6354 * correctly; this is just the minimum we can do - assume
6355 * we don't actually have any channel positions. */
6356 gst_caps_set_simple (stream->caps,
6357 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
6363 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
6364 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
6365 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
6366 gst_pad_set_active (stream->pad, TRUE);
6368 gst_pad_use_fixed_caps (stream->pad);
6370 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
6371 if (stream->new_stream) {
6374 GstStreamFlags stream_flags;
6377 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
6380 if (gst_event_parse_group_id (event, &qtdemux->group_id))
6381 qtdemux->have_group_id = TRUE;
6383 qtdemux->have_group_id = FALSE;
6384 gst_event_unref (event);
6385 } else if (!qtdemux->have_group_id) {
6386 qtdemux->have_group_id = TRUE;
6387 qtdemux->group_id = gst_util_group_id_next ();
6390 stream->new_stream = FALSE;
6392 gst_pad_create_stream_id_printf (stream->pad,
6393 GST_ELEMENT_CAST (qtdemux), "%03u", stream->track_id);
6394 event = gst_event_new_stream_start (stream_id);
6395 if (qtdemux->have_group_id)
6396 gst_event_set_group_id (event, qtdemux->group_id);
6397 stream_flags = GST_STREAM_FLAG_NONE;
6398 if (stream->disabled)
6399 stream_flags |= GST_STREAM_FLAG_UNSELECT;
6401 stream_flags |= GST_STREAM_FLAG_SPARSE;
6402 gst_event_set_stream_flags (event, stream_flags);
6403 gst_pad_push_event (stream->pad, event);
6406 gst_pad_set_caps (stream->pad, stream->caps);
6407 stream->new_caps = FALSE;
6413 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
6414 QtDemuxStream * stream, GstTagList * list)
6416 /* consistent default for push based mode */
6417 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
6419 if (stream->subtype == FOURCC_vide) {
6420 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
6423 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
6426 gst_qtdemux_configure_stream (qtdemux, stream);
6427 qtdemux->n_video_streams++;
6428 } else if (stream->subtype == FOURCC_soun) {
6429 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
6432 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
6434 gst_qtdemux_configure_stream (qtdemux, stream);
6435 qtdemux->n_audio_streams++;
6436 } else if (stream->subtype == FOURCC_strm) {
6437 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
6438 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
6439 || stream->subtype == FOURCC_sbtl) {
6440 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
6443 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
6445 gst_qtdemux_configure_stream (qtdemux, stream);
6446 qtdemux->n_sub_streams++;
6447 } else if (stream->caps) {
6448 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
6451 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
6453 gst_qtdemux_configure_stream (qtdemux, stream);
6454 qtdemux->n_video_streams++;
6456 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
6461 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
6462 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
6463 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
6464 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
6466 if (stream->pending_tags)
6467 gst_tag_list_unref (stream->pending_tags);
6468 stream->pending_tags = list;
6470 /* global tags go on each pad anyway */
6471 stream->send_global_tags = TRUE;
6475 gst_tag_list_unref (list);
6479 /* find next atom with @fourcc starting at @offset */
6480 static GstFlowReturn
6481 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
6482 guint64 * length, guint32 fourcc)
6488 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
6489 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
6495 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
6496 if (G_UNLIKELY (ret != GST_FLOW_OK))
6498 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
6501 gst_buffer_unref (buf);
6504 gst_buffer_map (buf, &map, GST_MAP_READ);
6505 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
6506 gst_buffer_unmap (buf, &map);
6507 gst_buffer_unref (buf);
6509 if (G_UNLIKELY (*length == 0)) {
6510 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
6511 ret = GST_FLOW_ERROR;
6515 if (lfourcc == fourcc) {
6516 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
6520 GST_LOG_OBJECT (qtdemux,
6521 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
6522 GST_FOURCC_ARGS (fourcc), *offset);
6531 /* might simply have had last one */
6532 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
6537 /* should only do something in pull mode */
6538 /* call with OBJECT lock */
6539 static GstFlowReturn
6540 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
6542 guint64 length, offset;
6543 GstBuffer *buf = NULL;
6544 GstFlowReturn ret = GST_FLOW_OK;
6545 GstFlowReturn res = GST_FLOW_OK;
6548 offset = qtdemux->moof_offset;
6549 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
6552 GST_DEBUG_OBJECT (qtdemux, "no next moof");
6553 return GST_FLOW_EOS;
6556 /* best not do pull etc with lock held */
6557 GST_OBJECT_UNLOCK (qtdemux);
6559 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
6560 if (ret != GST_FLOW_OK)
6563 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
6564 if (G_UNLIKELY (ret != GST_FLOW_OK))
6566 gst_buffer_map (buf, &map, GST_MAP_READ);
6567 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
6568 gst_buffer_unmap (buf, &map);
6569 gst_buffer_unref (buf);
6574 gst_buffer_unmap (buf, &map);
6575 gst_buffer_unref (buf);
6579 /* look for next moof */
6580 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
6581 if (G_UNLIKELY (ret != GST_FLOW_OK))
6585 GST_OBJECT_LOCK (qtdemux);
6587 qtdemux->moof_offset = offset;
6593 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
6595 res = GST_FLOW_ERROR;
6600 /* maybe upstream temporarily flushing */
6601 if (ret != GST_FLOW_FLUSHING) {
6602 GST_DEBUG_OBJECT (qtdemux, "no next moof");
6605 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
6606 /* resume at current position next time */
6613 /* initialise bytereaders for stbl sub-atoms */
6615 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
6617 stream->stbl_index = -1; /* no samples have yet been parsed */
6618 stream->sample_index = -1;
6620 /* time-to-sample atom */
6621 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
6624 /* copy atom data into a new buffer for later use */
6625 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
6627 /* skip version + flags */
6628 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
6629 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
6631 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
6633 /* make sure there's enough data */
6634 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
6635 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
6636 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
6637 stream->n_sample_times);
6638 if (!stream->n_sample_times)
6642 /* sync sample atom */
6643 stream->stps_present = FALSE;
6644 if ((stream->stss_present =
6645 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
6646 &stream->stss) ? TRUE : FALSE) == TRUE) {
6647 /* copy atom data into a new buffer for later use */
6648 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
6650 /* skip version + flags */
6651 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
6652 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
6655 if (stream->n_sample_syncs) {
6656 /* make sure there's enough data */
6657 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
6661 /* partial sync sample atom */
6662 if ((stream->stps_present =
6663 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
6664 &stream->stps) ? TRUE : FALSE) == TRUE) {
6665 /* copy atom data into a new buffer for later use */
6666 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
6668 /* skip version + flags */
6669 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
6670 !gst_byte_reader_get_uint32_be (&stream->stps,
6671 &stream->n_sample_partial_syncs))
6674 /* if there are no entries, the stss table contains the real
6676 if (stream->n_sample_partial_syncs) {
6677 /* make sure there's enough data */
6678 if (!qt_atom_parser_has_chunks (&stream->stps,
6679 stream->n_sample_partial_syncs, 4))
6686 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
6689 /* copy atom data into a new buffer for later use */
6690 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
6692 /* skip version + flags */
6693 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
6694 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
6697 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
6700 if (!stream->n_samples)
6703 /* sample-to-chunk atom */
6704 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
6707 /* copy atom data into a new buffer for later use */
6708 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
6710 /* skip version + flags */
6711 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
6712 !gst_byte_reader_get_uint32_be (&stream->stsc,
6713 &stream->n_samples_per_chunk))
6716 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
6717 stream->n_samples_per_chunk);
6719 /* make sure there's enough data */
6720 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
6726 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
6727 stream->co_size = sizeof (guint32);
6728 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
6730 stream->co_size = sizeof (guint64);
6734 /* copy atom data into a new buffer for later use */
6735 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
6737 /* skip version + flags */
6738 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
6741 /* chunks_are_samples == TRUE means treat chunks as samples */
6742 stream->chunks_are_samples = stream->sample_size && !stream->sampled;
6743 if (stream->chunks_are_samples) {
6744 /* treat chunks as samples */
6745 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
6748 /* skip number of entries */
6749 if (!gst_byte_reader_skip (&stream->stco, 4))
6752 /* make sure there are enough data in the stsz atom */
6753 if (!stream->sample_size) {
6754 /* different sizes for each sample */
6755 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
6760 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
6761 stream->n_samples, (guint) sizeof (QtDemuxSample),
6762 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
6764 if (stream->n_samples >=
6765 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
6766 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
6767 "be larger than %uMB (broken file?)", stream->n_samples,
6768 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
6772 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
6773 if (!stream->samples) {
6774 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
6779 /* composition time-to-sample */
6780 if ((stream->ctts_present =
6781 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
6782 &stream->ctts) ? TRUE : FALSE) == TRUE) {
6783 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
6785 /* copy atom data into a new buffer for later use */
6786 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
6788 /* skip version + flags */
6789 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
6790 || !gst_byte_reader_get_uint32_be (&stream->ctts,
6791 &stream->n_composition_times))
6794 /* make sure there's enough data */
6795 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
6799 /* This is optional, if missing we iterate the ctts */
6800 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
6801 if (!gst_byte_reader_skip (&cslg, 1 + 3)
6802 || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
6803 g_free ((gpointer) cslg.data);
6807 gint32 cslg_least = 0;
6808 guint num_entries, pos;
6811 pos = gst_byte_reader_get_pos (&stream->ctts);
6812 num_entries = stream->n_composition_times;
6814 stream->cslg_shift = 0;
6816 for (i = 0; i < num_entries; i++) {
6819 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
6820 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
6822 if (offset < cslg_least)
6823 cslg_least = offset;
6827 stream->cslg_shift = ABS (cslg_least);
6829 stream->cslg_shift = 0;
6831 /* reset the reader so we can generate sample table */
6832 gst_byte_reader_set_pos (&stream->ctts, pos);
6835 /* Ensure the cslg_shift value is consistent so we can use it
6836 * unconditionnally to produce TS and Segment */
6837 stream->cslg_shift = 0;
6844 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
6845 (_("This file is corrupt and cannot be played.")), (NULL));
6850 gst_qtdemux_stbl_free (stream);
6851 if (!qtdemux->fragmented) {
6852 /* not quite good */
6853 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
6856 /* may pick up samples elsewhere */
6862 /* collect samples from the next sample to be parsed up to sample @n for @stream
6863 * by reading the info from @stbl
6865 * This code can be executed from both the streaming thread and the seeking
6866 * thread so it takes the object lock to protect itself
6869 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
6872 QtDemuxSample *samples, *first, *cur, *last;
6873 guint32 n_samples_per_chunk;
6876 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
6877 GST_FOURCC_FORMAT ", pad %s", GST_FOURCC_ARGS (stream->fourcc),
6878 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
6880 n_samples = stream->n_samples;
6883 goto out_of_samples;
6885 GST_OBJECT_LOCK (qtdemux);
6886 if (n <= stream->stbl_index)
6887 goto already_parsed;
6889 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
6891 if (!stream->stsz.data) {
6892 /* so we already parsed and passed all the moov samples;
6893 * onto fragmented ones */
6894 g_assert (qtdemux->fragmented);
6898 /* pointer to the sample table */
6899 samples = stream->samples;
6901 /* starts from -1, moves to the next sample index to parse */
6902 stream->stbl_index++;
6904 /* keep track of the first and last sample to fill */
6905 first = &samples[stream->stbl_index];
6908 if (!stream->chunks_are_samples) {
6909 /* set the sample sizes */
6910 if (stream->sample_size == 0) {
6911 /* different sizes for each sample */
6912 for (cur = first; cur <= last; cur++) {
6913 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
6914 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
6915 (guint) (cur - samples), cur->size);
6918 /* samples have the same size */
6919 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
6920 for (cur = first; cur <= last; cur++)
6921 cur->size = stream->sample_size;
6925 n_samples_per_chunk = stream->n_samples_per_chunk;
6928 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
6931 if (stream->stsc_chunk_index >= stream->last_chunk
6932 || stream->stsc_chunk_index < stream->first_chunk) {
6933 stream->first_chunk =
6934 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
6935 stream->samples_per_chunk =
6936 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
6937 gst_byte_reader_skip_unchecked (&stream->stsc, 4);
6939 /* chunk numbers are counted from 1 it seems */
6940 if (G_UNLIKELY (stream->first_chunk == 0))
6943 --stream->first_chunk;
6945 /* the last chunk of each entry is calculated by taking the first chunk
6946 * of the next entry; except if there is no next, where we fake it with
6948 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
6949 stream->last_chunk = G_MAXUINT32;
6951 stream->last_chunk =
6952 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
6953 if (G_UNLIKELY (stream->last_chunk == 0))
6956 --stream->last_chunk;
6959 GST_LOG_OBJECT (qtdemux,
6960 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
6961 stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
6963 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
6966 if (stream->last_chunk != G_MAXUINT32) {
6967 if (!qt_atom_parser_peek_sub (&stream->stco,
6968 stream->first_chunk * stream->co_size,
6969 (stream->last_chunk - stream->first_chunk) * stream->co_size,
6974 stream->co_chunk = stream->stco;
6975 if (!gst_byte_reader_skip (&stream->co_chunk,
6976 stream->first_chunk * stream->co_size))
6980 stream->stsc_chunk_index = stream->first_chunk;
6983 last_chunk = stream->last_chunk;
6985 if (stream->chunks_are_samples) {
6986 cur = &samples[stream->stsc_chunk_index];
6988 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
6991 stream->stsc_chunk_index = j;
6996 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
6999 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
7000 "%" G_GUINT64_FORMAT, j, cur->offset);
7002 if (stream->samples_per_frame * stream->bytes_per_frame) {
7004 (stream->samples_per_chunk * stream->n_channels) /
7005 stream->samples_per_frame * stream->bytes_per_frame;
7007 cur->size = stream->samples_per_chunk;
7010 GST_DEBUG_OBJECT (qtdemux,
7011 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
7012 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
7013 stream->stco_sample_index)), cur->size);
7015 cur->timestamp = stream->stco_sample_index;
7016 cur->duration = stream->samples_per_chunk;
7017 cur->keyframe = TRUE;
7020 stream->stco_sample_index += stream->samples_per_chunk;
7022 stream->stsc_chunk_index = j;
7024 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
7025 guint32 samples_per_chunk;
7026 guint64 chunk_offset;
7028 if (!stream->stsc_sample_index
7029 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
7030 &stream->chunk_offset))
7033 samples_per_chunk = stream->samples_per_chunk;
7034 chunk_offset = stream->chunk_offset;
7036 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
7037 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
7038 G_GUINT64_FORMAT " and size %d",
7039 (guint) (cur - samples), chunk_offset, cur->size);
7041 cur->offset = chunk_offset;
7042 chunk_offset += cur->size;
7045 if (G_UNLIKELY (cur > last)) {
7047 stream->stsc_sample_index = k + 1;
7048 stream->chunk_offset = chunk_offset;
7049 stream->stsc_chunk_index = j;
7053 stream->stsc_sample_index = 0;
7055 stream->stsc_chunk_index = j;
7057 stream->stsc_index++;
7060 if (stream->chunks_are_samples)
7064 guint32 n_sample_times;
7066 n_sample_times = stream->n_sample_times;
7069 for (i = stream->stts_index; i < n_sample_times; i++) {
7070 guint32 stts_samples;
7071 gint32 stts_duration;
7074 if (stream->stts_sample_index >= stream->stts_samples
7075 || !stream->stts_sample_index) {
7077 stream->stts_samples =
7078 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
7079 stream->stts_duration =
7080 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
7082 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
7083 i, stream->stts_samples, stream->stts_duration);
7085 stream->stts_sample_index = 0;
7088 stts_samples = stream->stts_samples;
7089 stts_duration = stream->stts_duration;
7090 stts_time = stream->stts_time;
7092 for (j = stream->stts_sample_index; j < stts_samples; j++) {
7093 GST_DEBUG_OBJECT (qtdemux,
7094 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
7095 (guint) (cur - samples), j,
7096 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
7098 cur->timestamp = stts_time;
7099 cur->duration = stts_duration;
7101 /* avoid 32-bit wrap-around,
7102 * but still mind possible 'negative' duration */
7103 stts_time += (gint64) stts_duration;
7106 if (G_UNLIKELY (cur > last)) {
7108 stream->stts_time = stts_time;
7109 stream->stts_sample_index = j + 1;
7113 stream->stts_sample_index = 0;
7114 stream->stts_time = stts_time;
7115 stream->stts_index++;
7117 /* fill up empty timestamps with the last timestamp, this can happen when
7118 * the last samples do not decode and so we don't have timestamps for them.
7119 * We however look at the last timestamp to estimate the track length so we
7120 * need something in here. */
7121 for (; cur < last; cur++) {
7122 GST_DEBUG_OBJECT (qtdemux,
7123 "fill sample %d: timestamp %" GST_TIME_FORMAT,
7124 (guint) (cur - samples),
7125 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
7126 cur->timestamp = stream->stts_time;
7132 /* sample sync, can be NULL */
7133 if (stream->stss_present == TRUE) {
7134 guint32 n_sample_syncs;
7136 n_sample_syncs = stream->n_sample_syncs;
7138 if (!n_sample_syncs) {
7139 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
7140 stream->all_keyframe = TRUE;
7142 for (i = stream->stss_index; i < n_sample_syncs; i++) {
7143 /* note that the first sample is index 1, not 0 */
7146 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
7148 if (G_LIKELY (index > 0 && index <= n_samples)) {
7150 samples[index].keyframe = TRUE;
7151 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
7152 /* and exit if we have enough samples */
7153 if (G_UNLIKELY (index >= n)) {
7160 stream->stss_index = i;
7163 /* stps marks partial sync frames like open GOP I-Frames */
7164 if (stream->stps_present == TRUE) {
7165 guint32 n_sample_partial_syncs;
7167 n_sample_partial_syncs = stream->n_sample_partial_syncs;
7169 /* if there are no entries, the stss table contains the real
7171 if (n_sample_partial_syncs) {
7172 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
7173 /* note that the first sample is index 1, not 0 */
7176 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
7178 if (G_LIKELY (index > 0 && index <= n_samples)) {
7180 samples[index].keyframe = TRUE;
7181 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
7182 /* and exit if we have enough samples */
7183 if (G_UNLIKELY (index >= n)) {
7190 stream->stps_index = i;
7194 /* no stss, all samples are keyframes */
7195 stream->all_keyframe = TRUE;
7196 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
7201 /* composition time to sample */
7202 if (stream->ctts_present == TRUE) {
7203 guint32 n_composition_times;
7205 gint32 ctts_soffset;
7207 /* Fill in the pts_offsets */
7209 n_composition_times = stream->n_composition_times;
7211 for (i = stream->ctts_index; i < n_composition_times; i++) {
7212 if (stream->ctts_sample_index >= stream->ctts_count
7213 || !stream->ctts_sample_index) {
7214 stream->ctts_count =
7215 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
7216 stream->ctts_soffset =
7217 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
7218 stream->ctts_sample_index = 0;
7221 ctts_count = stream->ctts_count;
7222 ctts_soffset = stream->ctts_soffset;
7224 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
7225 cur->pts_offset = ctts_soffset;
7228 if (G_UNLIKELY (cur > last)) {
7230 stream->ctts_sample_index = j + 1;
7234 stream->ctts_sample_index = 0;
7235 stream->ctts_index++;
7239 stream->stbl_index = n;
7240 /* if index has been completely parsed, free data that is no-longer needed */
7241 if (n + 1 == stream->n_samples) {
7242 gst_qtdemux_stbl_free (stream);
7243 GST_DEBUG_OBJECT (qtdemux,
7244 "parsed all available samples; checking for more");
7245 while (n + 1 == stream->n_samples)
7246 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
7249 GST_OBJECT_UNLOCK (qtdemux);
7256 GST_LOG_OBJECT (qtdemux,
7257 "Tried to parse up to sample %u but this sample has already been parsed",
7259 /* if fragmented, there may be more */
7260 if (qtdemux->fragmented && n == stream->stbl_index)
7262 GST_OBJECT_UNLOCK (qtdemux);
7268 GST_LOG_OBJECT (qtdemux,
7269 "Tried to parse up to sample %u but there are only %u samples", n + 1,
7271 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7272 (_("This file is corrupt and cannot be played.")), (NULL));
7277 GST_OBJECT_UNLOCK (qtdemux);
7278 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7279 (_("This file is corrupt and cannot be played.")), (NULL));
7284 /* collect all segment info for @stream.
7287 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
7292 /* parse and prepare segment info from the edit list */
7293 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
7294 stream->n_segments = 0;
7295 stream->segments = NULL;
7296 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
7304 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
7305 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
7308 buffer = elst->data;
7310 n_segments = QT_UINT32 (buffer + 12);
7312 /* we might allocate a bit too much, at least allocate 1 segment */
7313 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
7315 /* segments always start from 0 */
7319 for (i = 0; i < n_segments; i++) {
7322 QtDemuxSegment *segment;
7325 media_time = QT_UINT32 (buffer + 20 + i * 12);
7326 duration = QT_UINT32 (buffer + 16 + i * 12);
7328 segment = &stream->segments[count++];
7330 /* time and duration expressed in global timescale */
7331 segment->time = stime;
7332 /* add non scaled values so we don't cause roundoff errors */
7334 stime = QTTIME_TO_GSTTIME (qtdemux, time);
7335 segment->stop_time = stime;
7336 segment->duration = stime - segment->time;
7338 segment->trak_media_start = media_time;
7339 /* media_time expressed in stream timescale */
7340 if (media_time != G_MAXUINT32) {
7341 segment->media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
7342 segment->media_stop = segment->media_start + segment->duration;
7344 segment->media_start = GST_CLOCK_TIME_NONE;
7345 segment->media_stop = GST_CLOCK_TIME_NONE;
7347 rate_int = GST_READ_UINT32_BE (buffer + 24 + i * 12);
7349 if (rate_int <= 1) {
7350 /* 0 is not allowed, some programs write 1 instead of the floating point
7352 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
7356 segment->rate = rate_int / 65536.0;
7359 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
7360 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
7361 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
7362 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
7363 i, GST_TIME_ARGS (segment->time),
7364 GST_TIME_ARGS (segment->duration),
7365 GST_TIME_ARGS (segment->media_start), media_time,
7366 GST_TIME_ARGS (segment->media_stop),
7367 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
7369 if (segment->stop_time > qtdemux->segment.stop) {
7370 GST_WARNING_OBJECT (qtdemux, "Segment %d "
7371 " extends to %" GST_TIME_FORMAT
7372 " past the end of the file duration %" GST_TIME_FORMAT
7373 " it will be truncated", i, GST_TIME_ARGS (segment->stop_time),
7374 GST_TIME_ARGS (qtdemux->segment.stop));
7375 qtdemux->segment.stop = segment->stop_time;
7378 GST_DEBUG_OBJECT (qtdemux, "found %d segments", count);
7379 stream->n_segments = count;
7383 /* push based does not handle segments, so act accordingly here,
7384 * and warn if applicable */
7385 if (!qtdemux->pullbased) {
7386 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
7387 /* remove and use default one below, we stream like it anyway */
7388 g_free (stream->segments);
7389 stream->segments = NULL;
7390 stream->n_segments = 0;
7393 /* no segments, create one to play the complete trak */
7394 if (stream->n_segments == 0) {
7395 GstClockTime stream_duration =
7396 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
7398 if (stream->segments == NULL)
7399 stream->segments = g_new (QtDemuxSegment, 1);
7401 /* represent unknown our way */
7402 if (stream_duration == 0)
7403 stream_duration = GST_CLOCK_TIME_NONE;
7405 stream->segments[0].time = 0;
7406 stream->segments[0].stop_time = stream_duration;
7407 stream->segments[0].duration = stream_duration;
7408 stream->segments[0].media_start = 0;
7409 stream->segments[0].media_stop = stream_duration;
7410 stream->segments[0].rate = 1.0;
7411 stream->segments[0].trak_media_start = 0;
7413 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
7414 GST_TIME_ARGS (stream_duration));
7415 stream->n_segments = 1;
7416 stream->dummy_segment = TRUE;
7418 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
7424 * Parses the stsd atom of a svq3 trak looking for
7425 * the SMI and gama atoms.
7428 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
7429 guint8 ** gamma, GstBuffer ** seqh)
7431 guint8 *_gamma = NULL;
7432 GstBuffer *_seqh = NULL;
7433 guint8 *stsd_data = stsd->data;
7434 guint32 length = QT_UINT32 (stsd_data);
7438 GST_WARNING_OBJECT (qtdemux, "stsd too short");
7444 version = QT_UINT16 (stsd_data);
7449 while (length > 8) {
7450 guint32 fourcc, size;
7452 size = QT_UINT32 (stsd_data);
7453 fourcc = QT_FOURCC (stsd_data + 4);
7454 data = stsd_data + 8;
7457 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
7458 "svq3 atom parsing");
7467 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
7468 " for gama atom, expected 12", size);
7473 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
7475 if (_seqh != NULL) {
7476 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
7477 " found, ignoring");
7479 seqh_size = QT_UINT32 (data + 4);
7480 if (seqh_size > 0) {
7481 _seqh = gst_buffer_new_and_alloc (seqh_size);
7482 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
7489 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
7490 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
7494 if (size <= length) {
7500 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
7503 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
7504 G_GUINT16_FORMAT, version);
7515 gst_buffer_unref (_seqh);
7520 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
7527 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
7528 * atom that might contain a 'data' atom with the rtsp uri.
7529 * This case was reported in bug #597497, some info about
7530 * the hndl atom can be found in TN1195
7532 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
7533 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
7536 guint32 dref_num_entries = 0;
7537 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
7538 gst_byte_reader_skip (&dref, 4) &&
7539 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
7542 /* search dref entries for hndl atom */
7543 for (i = 0; i < dref_num_entries; i++) {
7544 guint32 size = 0, type;
7545 guint8 string_len = 0;
7546 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
7547 qt_atom_parser_get_fourcc (&dref, &type)) {
7548 if (type == FOURCC_hndl) {
7549 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
7551 /* skip data reference handle bytes and the
7552 * following pascal string and some extra 4
7553 * bytes I have no idea what are */
7554 if (!gst_byte_reader_skip (&dref, 4) ||
7555 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
7556 !gst_byte_reader_skip (&dref, string_len + 4)) {
7557 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
7561 /* iterate over the atoms to find the data atom */
7562 while (gst_byte_reader_get_remaining (&dref) >= 8) {
7566 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
7567 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
7568 if (atom_type == FOURCC_data) {
7569 const guint8 *uri_aux = NULL;
7571 /* found the data atom that might contain the rtsp uri */
7572 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
7573 "hndl atom, interpreting it as an URI");
7574 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
7576 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
7577 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
7579 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
7580 "didn't contain a rtsp address");
7582 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
7587 /* skipping to the next entry */
7588 if (!gst_byte_reader_skip (&dref, atom_size - 8))
7591 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
7598 /* skip to the next entry */
7599 if (!gst_byte_reader_skip (&dref, size - 8))
7602 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
7605 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
7611 #define AMR_NB_ALL_MODES 0x81ff
7612 #define AMR_WB_ALL_MODES 0x83ff
7614 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
7616 /* The 'damr' atom is of the form:
7618 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
7619 * 32 b 8 b 16 b 8 b 8 b
7621 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
7622 * represents the highest mode used in the stream (and thus the maximum
7623 * bitrate), with a couple of special cases as seen below.
7626 /* Map of frame type ID -> bitrate */
7627 static const guint nb_bitrates[] = {
7628 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
7630 static const guint wb_bitrates[] = {
7631 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
7637 gst_buffer_map (buf, &map, GST_MAP_READ);
7639 if (map.size != 0x11) {
7640 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
7644 if (QT_FOURCC (map.data + 4) != GST_MAKE_FOURCC ('d', 'a', 'm', 'r')) {
7645 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
7646 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
7650 mode_set = QT_UINT16 (map.data + 13);
7652 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
7653 max_mode = 7 + (wb ? 1 : 0);
7655 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
7656 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
7658 if (max_mode == -1) {
7659 GST_DEBUG ("No mode indication was found (mode set) = %x",
7664 gst_buffer_unmap (buf, &map);
7665 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
7668 gst_buffer_unmap (buf, &map);
7673 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
7674 GstByteReader * reader, guint32 * matrix, const gchar * atom)
7677 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
7683 if (gst_byte_reader_get_remaining (reader) < 36)
7686 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
7687 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
7688 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
7689 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
7690 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
7691 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
7692 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
7693 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
7694 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
7696 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
7697 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
7698 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
7700 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
7701 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
7703 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
7704 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
7711 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
7712 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
7719 * This macro will only compare value abdegh, it expects cfi to have already
7722 #define QTCHECK_MATRIX(m,a,b,d,e,g,h) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
7723 (m)[3] == (d << 16) && (m)[4] == (e << 16) && \
7724 (m)[6] == (g << 16) && (m)[7] == (h << 16))
7726 /* only handle the cases where the last column has standard values */
7727 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
7728 const gchar *rotation_tag = NULL;
7730 /* no rotation needed */
7731 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1, 0, 0)) {
7733 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0,
7734 stream->display_height, 0)) {
7735 rotation_tag = "rotate-90";
7736 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16,
7737 stream->display_width, stream->display_height)) {
7738 rotation_tag = "rotate-180";
7739 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0, 0,
7740 stream->display_width)) {
7741 rotation_tag = "rotate-270";
7743 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
7746 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
7748 if (rotation_tag != NULL) {
7749 if (*taglist == NULL)
7750 *taglist = gst_tag_list_new_empty ();
7751 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
7752 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
7755 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
7760 * With each track we associate a new QtDemuxStream that contains all the info
7762 * traks that do not decode to something (like strm traks) will not have a pad.
7765 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
7784 QtDemuxStream *stream = NULL;
7785 gboolean new_stream = FALSE;
7786 gchar *codec = NULL;
7787 const guint8 *stsd_data;
7788 guint16 lang_code; /* quicktime lang code or packed iso code */
7790 guint32 tkhd_flags = 0;
7791 guint8 tkhd_version = 0;
7793 guint value_size, stsd_len, len;
7796 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
7798 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
7799 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
7800 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
7803 /* pick between 64 or 32 bits */
7804 value_size = tkhd_version == 1 ? 8 : 4;
7805 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
7806 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
7809 if (!qtdemux->got_moov) {
7810 if (qtdemux_find_stream (qtdemux, track_id))
7811 goto existing_stream;
7812 stream = _create_stream ();
7813 stream->track_id = track_id;
7816 stream = qtdemux_find_stream (qtdemux, track_id);
7818 GST_WARNING_OBJECT (qtdemux, "Stream not found, going to ignore it");
7823 if (stream->pending_tags == NULL)
7824 stream->pending_tags = gst_tag_list_new_empty ();
7826 if ((tkhd_flags & 1) == 0)
7827 stream->disabled = TRUE;
7829 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
7830 tkhd_version, tkhd_flags, stream->track_id);
7832 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
7835 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
7836 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
7837 if (qtdemux->major_brand != FOURCC_mjp2 ||
7838 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
7842 len = QT_UINT32 ((guint8 *) mdhd->data);
7843 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
7844 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
7845 if (version == 0x01000000) {
7848 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
7849 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
7850 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
7854 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
7855 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
7856 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
7859 if (lang_code < 0x400) {
7860 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
7861 } else if (lang_code == 0x7fff) {
7862 stream->lang_id[0] = 0; /* unspecified */
7864 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
7865 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
7866 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
7867 stream->lang_id[3] = 0;
7870 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
7872 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
7874 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
7875 lang_code, stream->lang_id);
7877 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
7880 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
7881 /* chapters track reference */
7882 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
7884 gsize length = GST_READ_UINT32_BE (chap->data);
7885 if (qtdemux->chapters_track_id)
7886 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
7889 qtdemux->chapters_track_id =
7890 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
7895 /* fragmented files may have bogus duration in moov */
7896 if (!qtdemux->fragmented &&
7897 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
7898 guint64 tdur1, tdur2;
7900 /* don't overflow */
7901 tdur1 = stream->timescale * (guint64) qtdemux->duration;
7902 tdur2 = qtdemux->timescale * (guint64) stream->duration;
7905 * some of those trailers, nowadays, have prologue images that are
7906 * themselves vide tracks as well. I haven't really found a way to
7907 * identify those yet, except for just looking at their duration. */
7908 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
7909 GST_WARNING_OBJECT (qtdemux,
7910 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
7911 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
7912 "found, assuming preview image or something; skipping track",
7913 stream->duration, stream->timescale, qtdemux->duration,
7914 qtdemux->timescale);
7920 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
7923 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
7924 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
7926 len = QT_UINT32 ((guint8 *) hdlr->data);
7928 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
7929 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
7930 GST_FOURCC_ARGS (stream->subtype));
7932 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
7935 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
7938 /*parse svmi header if existing */
7939 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
7941 len = QT_UINT32 ((guint8 *) svmi->data);
7942 version = QT_UINT32 ((guint8 *) svmi->data + 8);
7944 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
7945 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
7946 guint8 frame_type, frame_layout;
7948 /* MPEG-A stereo video */
7949 if (qtdemux->major_brand == FOURCC_ss02)
7950 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
7952 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
7953 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
7954 switch (frame_type) {
7956 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
7959 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
7962 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
7965 /* mode 3 is primary/secondary view sequence, ie
7966 * left/right views in separate tracks. See section 7.2
7967 * of ISO/IEC 23000-11:2009 */
7968 GST_FIXME_OBJECT (qtdemux,
7969 "Implement stereo video in separate streams");
7972 if ((frame_layout & 0x1) == 0)
7973 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
7975 GST_LOG_OBJECT (qtdemux,
7976 "StereoVideo: composition type: %u, is_left_first: %u",
7977 frame_type, frame_layout);
7978 stream->multiview_mode = mode;
7979 stream->multiview_flags = flags;
7984 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
7986 stsd_data = (const guint8 *) stsd->data;
7988 /* stsd should at least have one entry */
7989 stsd_len = QT_UINT32 (stsd_data);
7990 if (stsd_len < 24) {
7991 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
7992 if (stream->subtype == FOURCC_vivo) {
8000 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
8002 /* and that entry should fit within stsd */
8003 len = QT_UINT32 (stsd_data + 16);
8004 if (len > stsd_len + 16)
8007 stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
8008 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
8009 GST_FOURCC_ARGS (stream->fourcc));
8010 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
8012 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi) ||
8013 ((fourcc & 0x00FFFFFF) == GST_MAKE_FOURCC ('e', 'n', 'c', 0)))
8014 goto error_encrypted;
8016 if (stream->subtype == FOURCC_vide) {
8017 guint32 w = 0, h = 0;
8019 gint depth, palette_size, palette_count;
8021 guint32 *palette_data = NULL;
8023 stream->sampled = TRUE;
8025 /* version 1 uses some 64-bit ints */
8026 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
8029 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
8032 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
8033 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
8036 stream->display_width = w >> 16;
8037 stream->display_height = h >> 16;
8039 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
8040 &stream->pending_tags);
8046 stream->width = QT_UINT16 (stsd_data + offset + 32);
8047 stream->height = QT_UINT16 (stsd_data + offset + 34);
8048 stream->fps_n = 0; /* this is filled in later */
8049 stream->fps_d = 0; /* this is filled in later */
8050 stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
8051 stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
8053 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
8054 stream->width, stream->height, stream->bits_per_sample,
8055 stream->color_table_id);
8057 depth = stream->bits_per_sample;
8059 /* more than 32 bits means grayscale */
8060 gray = (depth > 32);
8061 /* low 32 bits specify the depth */
8064 /* different number of palette entries is determined by depth. */
8066 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
8067 palette_count = (1 << depth);
8068 palette_size = palette_count * 4;
8070 if (stream->color_table_id) {
8071 switch (palette_count) {
8075 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
8078 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
8082 palette_data = g_memdup (ff_qt_grayscale_palette_16, palette_size);
8084 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
8088 palette_data = g_memdup (ff_qt_grayscale_palette_256, palette_size);
8090 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
8093 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
8094 (_("The video in this file might not play correctly.")),
8095 ("unsupported palette depth %d", depth));
8099 gint i, j, start, end;
8105 start = QT_UINT32 (stsd_data + offset + 86);
8106 palette_count = QT_UINT16 (stsd_data + offset + 90);
8107 end = QT_UINT16 (stsd_data + offset + 92);
8109 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
8110 start, end, palette_count);
8117 if (len < 94 + (end - start) * 8)
8120 /* palette is always the same size */
8121 palette_data = g_malloc0 (256 * 4);
8122 palette_size = 256 * 4;
8124 for (j = 0, i = start; i <= end; j++, i++) {
8127 a = QT_UINT16 (stsd_data + offset + 94 + (j * 8));
8128 r = QT_UINT16 (stsd_data + offset + 96 + (j * 8));
8129 g = QT_UINT16 (stsd_data + offset + 98 + (j * 8));
8130 b = QT_UINT16 (stsd_data + offset + 100 + (j * 8));
8132 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
8133 (g & 0xff00) | (b >> 8);
8138 qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
8139 if (G_UNLIKELY (!stream->caps)) {
8140 g_free (palette_data);
8141 goto unknown_stream;
8145 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
8146 GST_TAG_VIDEO_CODEC, codec, NULL);
8155 if (stream->rgb8_palette)
8156 gst_memory_unref (stream->rgb8_palette);
8157 stream->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
8158 palette_data, palette_size, 0, palette_size, palette_data, g_free);
8160 s = gst_caps_get_structure (stream->caps, 0);
8162 /* non-raw video has a palette_data property. raw video has the palette as
8163 * an extra plane that we append to the output buffers before we push
8165 if (!gst_structure_has_name (s, "video/x-raw")) {
8168 palette = gst_buffer_new ();
8169 gst_buffer_append_memory (palette, stream->rgb8_palette);
8170 stream->rgb8_palette = NULL;
8172 gst_caps_set_simple (stream->caps, "palette_data",
8173 GST_TYPE_BUFFER, palette, NULL);
8174 gst_buffer_unref (palette);
8176 } else if (palette_count != 0) {
8177 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
8178 (NULL), ("Unsupported palette depth %d", depth));
8181 GST_LOG_OBJECT (qtdemux, "frame count: %u",
8182 QT_UINT16 (stsd_data + offset + 48));
8186 /* pick 'the' stsd child */
8187 mp4v = qtdemux_tree_get_child_by_type (stsd, fourcc);
8189 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
8190 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
8194 const guint8 *pasp_data = (const guint8 *) pasp->data;
8196 stream->par_w = QT_UINT32 (pasp_data + 8);
8197 stream->par_h = QT_UINT32 (pasp_data + 12);
8204 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
8211 gint len = QT_UINT32 (stsd_data) - 0x66;
8212 const guint8 *avc_data = stsd_data + 0x66;
8215 while (len >= 0x8) {
8218 if (QT_UINT32 (avc_data) <= len)
8219 size = QT_UINT32 (avc_data) - 0x8;
8224 /* No real data, so break out */
8227 switch (QT_FOURCC (avc_data + 0x4)) {
8230 /* parse, if found */
8233 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
8235 /* First 4 bytes are the length of the atom, the next 4 bytes
8236 * are the fourcc, the next 1 byte is the version, and the
8237 * subsequent bytes are profile_tier_level structure like data. */
8238 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
8239 avc_data + 8 + 1, size - 1);
8240 buf = gst_buffer_new_and_alloc (size);
8241 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
8242 gst_caps_set_simple (stream->caps,
8243 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8244 gst_buffer_unref (buf);
8252 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
8254 /* First 4 bytes are the length of the atom, the next 4 bytes
8255 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
8256 * next 1 byte is the version, and the
8257 * subsequent bytes are sequence parameter set like data. */
8259 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
8261 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
8262 avc_data + 8 + 40 + 1, size - 1);
8264 buf = gst_buffer_new_and_alloc (size);
8265 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
8266 gst_caps_set_simple (stream->caps,
8267 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8268 gst_buffer_unref (buf);
8274 guint avg_bitrate, max_bitrate;
8276 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
8280 max_bitrate = QT_UINT32 (avc_data + 0xc);
8281 avg_bitrate = QT_UINT32 (avc_data + 0x10);
8283 if (!max_bitrate && !avg_bitrate)
8286 /* Some muxers seem to swap the average and maximum bitrates
8287 * (I'm looking at you, YouTube), so we swap for sanity. */
8288 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
8289 guint temp = avg_bitrate;
8291 avg_bitrate = max_bitrate;
8295 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
8296 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
8297 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
8299 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
8300 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
8301 GST_TAG_BITRATE, avg_bitrate, NULL);
8312 avc_data += size + 8;
8321 gint len = QT_UINT32 (stsd_data) - 0x66;
8322 const guint8 *hevc_data = stsd_data + 0x66;
8325 while (len >= 0x8) {
8328 if (QT_UINT32 (hevc_data) <= len)
8329 size = QT_UINT32 (hevc_data) - 0x8;
8334 /* No real data, so break out */
8337 switch (QT_FOURCC (hevc_data + 0x4)) {
8340 /* parse, if found */
8343 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
8345 /* First 4 bytes are the length of the atom, the next 4 bytes
8346 * are the fourcc, the next 1 byte is the version, and the
8347 * subsequent bytes are sequence parameter set like data. */
8348 gst_codec_utils_h265_caps_set_level_tier_and_profile
8349 (stream->caps, hevc_data + 8 + 1, size - 1);
8351 buf = gst_buffer_new_and_alloc (size);
8352 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
8353 gst_caps_set_simple (stream->caps,
8354 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8355 gst_buffer_unref (buf);
8362 hevc_data += size + 8;
8373 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
8374 GST_FOURCC_ARGS (fourcc));
8376 /* codec data might be in glbl extension atom */
8378 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
8384 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
8386 len = QT_UINT32 (data);
8389 buf = gst_buffer_new_and_alloc (len);
8390 gst_buffer_fill (buf, 0, data + 8, len);
8391 gst_caps_set_simple (stream->caps,
8392 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8393 gst_buffer_unref (buf);
8400 /* see annex I of the jpeg2000 spec */
8401 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
8403 const gchar *colorspace = NULL;
8405 guint32 ncomp_map = 0;
8406 gint32 *comp_map = NULL;
8407 guint32 nchan_def = 0;
8408 gint32 *chan_def = NULL;
8410 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
8411 /* some required atoms */
8412 mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
8415 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
8419 /* number of components; redundant with info in codestream, but useful
8421 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
8422 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
8424 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
8426 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
8429 GST_DEBUG_OBJECT (qtdemux, "found colr");
8430 /* extract colour space info */
8431 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
8432 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
8434 colorspace = "sRGB";
8437 colorspace = "GRAY";
8440 colorspace = "sYUV";
8448 /* colr is required, and only values 16, 17, and 18 are specified,
8449 so error if we have no colorspace */
8452 /* extract component mapping */
8453 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
8455 guint32 cmap_len = 0;
8457 cmap_len = QT_UINT32 (cmap->data);
8458 if (cmap_len >= 8) {
8459 /* normal box, subtract off header */
8461 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
8462 if (cmap_len % 4 == 0) {
8463 ncomp_map = (cmap_len / 4);
8464 comp_map = g_new0 (gint32, ncomp_map);
8465 for (i = 0; i < ncomp_map; i++) {
8468 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
8469 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
8470 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
8471 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
8476 /* extract channel definitions */
8477 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
8479 guint32 cdef_len = 0;
8481 cdef_len = QT_UINT32 (cdef->data);
8482 if (cdef_len >= 10) {
8483 /* normal box, subtract off header and len */
8485 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
8486 if (cdef_len % 6 == 0) {
8487 nchan_def = (cdef_len / 6);
8488 chan_def = g_new0 (gint32, nchan_def);
8489 for (i = 0; i < nchan_def; i++)
8491 for (i = 0; i < nchan_def; i++) {
8492 guint16 cn, typ, asoc;
8493 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
8494 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
8495 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
8496 if (cn < nchan_def) {
8499 chan_def[cn] = asoc;
8502 chan_def[cn] = 0; /* alpha */
8505 chan_def[cn] = -typ;
8513 gst_caps_set_simple (stream->caps,
8514 "num-components", G_TYPE_INT, ncomp, NULL);
8515 gst_caps_set_simple (stream->caps,
8516 "colorspace", G_TYPE_STRING, colorspace, NULL);
8519 GValue arr = { 0, };
8520 GValue elt = { 0, };
8522 g_value_init (&arr, GST_TYPE_ARRAY);
8523 g_value_init (&elt, G_TYPE_INT);
8524 for (i = 0; i < ncomp_map; i++) {
8525 g_value_set_int (&elt, comp_map[i]);
8526 gst_value_array_append_value (&arr, &elt);
8528 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
8529 "component-map", &arr);
8530 g_value_unset (&elt);
8531 g_value_unset (&arr);
8536 GValue arr = { 0, };
8537 GValue elt = { 0, };
8539 g_value_init (&arr, GST_TYPE_ARRAY);
8540 g_value_init (&elt, G_TYPE_INT);
8541 for (i = 0; i < nchan_def; i++) {
8542 g_value_set_int (&elt, chan_def[i]);
8543 gst_value_array_append_value (&arr, &elt);
8545 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
8546 "channel-definitions", &arr);
8547 g_value_unset (&elt);
8548 g_value_unset (&arr);
8552 /* some optional atoms */
8553 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
8554 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
8556 /* indicate possible fields in caps */
8558 data = (guint8 *) field->data + 8;
8560 gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
8561 (gint) * data, NULL);
8563 /* add codec_data if provided */
8568 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
8569 data = prefix->data;
8570 len = QT_UINT32 (data);
8573 buf = gst_buffer_new_and_alloc (len);
8574 gst_buffer_fill (buf, 0, data + 8, len);
8575 gst_caps_set_simple (stream->caps,
8576 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8577 gst_buffer_unref (buf);
8586 GstBuffer *seqh = NULL;
8587 guint8 *gamma_data = NULL;
8588 gint len = QT_UINT32 (stsd_data);
8590 qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
8592 gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
8593 QT_FP32 (gamma_data), NULL);
8596 /* sorry for the bad name, but we don't know what this is, other
8597 * than its own fourcc */
8598 gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
8602 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
8603 buf = gst_buffer_new_and_alloc (len);
8604 gst_buffer_fill (buf, 0, stsd_data, len);
8605 gst_caps_set_simple (stream->caps,
8606 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8607 gst_buffer_unref (buf);
8613 gst_caps_set_simple (stream->caps,
8614 "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
8621 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
8622 xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
8626 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
8630 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
8631 /* collect the headers and store them in a stream list so that we can
8632 * send them out first */
8633 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
8643 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
8644 ovc1 = qtdemux_tree_get_child_by_type (stsd, FOURCC_ovc1);
8647 ovc1_data = ovc1->data;
8648 ovc1_len = QT_UINT32 (ovc1_data);
8649 if (ovc1_len <= 198) {
8650 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
8653 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
8654 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
8655 gst_caps_set_simple (stream->caps,
8656 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8657 gst_buffer_unref (buf);
8660 case GST_MAKE_FOURCC ('v', 'c', '-', '1'):
8662 gint len = QT_UINT32 (stsd_data) - 0x66;
8663 const guint8 *vc1_data = stsd_data + 0x66;
8669 if (QT_UINT32 (vc1_data) <= len)
8670 size = QT_UINT32 (vc1_data) - 8;
8675 /* No real data, so break out */
8678 switch (QT_FOURCC (vc1_data + 0x4)) {
8679 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
8683 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
8684 buf = gst_buffer_new_and_alloc (size);
8685 gst_buffer_fill (buf, 0, vc1_data + 8, size);
8686 gst_caps_set_simple (stream->caps,
8687 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8688 gst_buffer_unref (buf);
8695 vc1_data += size + 8;
8704 GST_INFO_OBJECT (qtdemux,
8705 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
8706 GST_FOURCC_ARGS (fourcc), stream->caps);
8708 } else if (stream->subtype == FOURCC_soun) {
8709 int version, samplesize;
8710 guint16 compression_id;
8711 gboolean amrwb = FALSE;
8714 /* sample description entry (16) + sound sample description v0 (20) */
8718 version = QT_UINT32 (stsd_data + offset);
8719 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
8720 samplesize = QT_UINT16 (stsd_data + offset + 10);
8721 compression_id = QT_UINT16 (stsd_data + offset + 12);
8722 stream->rate = QT_FP32 (stsd_data + offset + 16);
8724 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
8725 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
8726 QT_UINT32 (stsd_data + offset + 4));
8727 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
8728 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
8729 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
8730 GST_LOG_OBJECT (qtdemux, "packet size: %d",
8731 QT_UINT16 (stsd_data + offset + 14));
8732 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
8734 if (compression_id == 0xfffe)
8735 stream->sampled = TRUE;
8737 /* first assume uncompressed audio */
8738 stream->bytes_per_sample = samplesize / 8;
8739 stream->samples_per_frame = stream->n_channels;
8740 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
8741 stream->samples_per_packet = stream->samples_per_frame;
8742 stream->bytes_per_packet = stream->bytes_per_sample;
8746 /* Yes, these have to be hard-coded */
8749 stream->samples_per_packet = 6;
8750 stream->bytes_per_packet = 1;
8751 stream->bytes_per_frame = 1 * stream->n_channels;
8752 stream->bytes_per_sample = 1;
8753 stream->samples_per_frame = 6 * stream->n_channels;
8758 stream->samples_per_packet = 3;
8759 stream->bytes_per_packet = 1;
8760 stream->bytes_per_frame = 1 * stream->n_channels;
8761 stream->bytes_per_sample = 1;
8762 stream->samples_per_frame = 3 * stream->n_channels;
8767 stream->samples_per_packet = 64;
8768 stream->bytes_per_packet = 34;
8769 stream->bytes_per_frame = 34 * stream->n_channels;
8770 stream->bytes_per_sample = 2;
8771 stream->samples_per_frame = 64 * stream->n_channels;
8777 stream->samples_per_packet = 1;
8778 stream->bytes_per_packet = 1;
8779 stream->bytes_per_frame = 1 * stream->n_channels;
8780 stream->bytes_per_sample = 1;
8781 stream->samples_per_frame = 1 * stream->n_channels;
8786 stream->samples_per_packet = 160;
8787 stream->bytes_per_packet = 33;
8788 stream->bytes_per_frame = 33 * stream->n_channels;
8789 stream->bytes_per_sample = 2;
8790 stream->samples_per_frame = 160 * stream->n_channels;
8797 if (version == 0x00010000) {
8798 /* sample description entry (16) + sound sample description v1 (20+16) */
8809 /* only parse extra decoding config for non-pcm audio */
8810 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
8811 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
8812 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
8813 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
8815 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
8816 stream->samples_per_packet);
8817 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
8818 stream->bytes_per_packet);
8819 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
8820 stream->bytes_per_frame);
8821 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
8822 stream->bytes_per_sample);
8824 if (!stream->sampled && stream->bytes_per_packet) {
8825 stream->samples_per_frame = (stream->bytes_per_frame /
8826 stream->bytes_per_packet) * stream->samples_per_packet;
8827 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
8828 stream->samples_per_frame);
8833 } else if (version == 0x00020000) {
8840 /* sample description entry (16) + sound sample description v2 (56) */
8844 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
8845 stream->rate = qtfp.fp;
8846 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
8848 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
8849 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
8850 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
8851 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
8852 QT_UINT32 (stsd_data + offset + 20));
8853 GST_LOG_OBJECT (qtdemux, "format flags: %X",
8854 QT_UINT32 (stsd_data + offset + 24));
8855 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
8856 QT_UINT32 (stsd_data + offset + 28));
8857 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
8858 QT_UINT32 (stsd_data + offset + 32));
8859 } else if (version != 0x00000) {
8860 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x", version);
8863 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc,
8864 stsd_data + 32, len - 16, &codec);
8872 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
8874 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
8876 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
8878 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
8881 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
8882 gst_caps_set_simple (stream->caps,
8883 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE", NULL);
8890 const guint8 *owma_data;
8891 const gchar *codec_name = NULL;
8895 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
8896 /* FIXME this should also be gst_riff_strf_auds,
8897 * but the latter one is actually missing bits-per-sample :( */
8902 gint32 nSamplesPerSec;
8903 gint32 nAvgBytesPerSec;
8905 gint16 wBitsPerSample;
8910 GST_DEBUG_OBJECT (qtdemux, "parse owma");
8911 owma = qtdemux_tree_get_child_by_type (stsd, FOURCC_owma);
8914 owma_data = owma->data;
8915 owma_len = QT_UINT32 (owma_data);
8916 if (owma_len <= 54) {
8917 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
8920 wfex = (WAVEFORMATEX *) (owma_data + 36);
8921 buf = gst_buffer_new_and_alloc (owma_len - 54);
8922 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
8923 if (wfex->wFormatTag == 0x0161) {
8924 codec_name = "Windows Media Audio";
8926 } else if (wfex->wFormatTag == 0x0162) {
8927 codec_name = "Windows Media Audio 9 Pro";
8929 } else if (wfex->wFormatTag == 0x0163) {
8930 codec_name = "Windows Media Audio 9 Lossless";
8931 /* is that correct? gstffmpegcodecmap.c is missing it, but
8932 * fluendo codec seems to support it */
8936 gst_caps_set_simple (stream->caps,
8937 "codec_data", GST_TYPE_BUFFER, buf,
8938 "wmaversion", G_TYPE_INT, version,
8939 "block_align", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->nBlockAlign),
8940 "bitrate", G_TYPE_INT, GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec),
8941 "width", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
8942 "depth", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
8944 gst_buffer_unref (buf);
8948 codec = g_strdup (codec_name);
8952 case GST_MAKE_FOURCC ('w', 'm', 'a', ' '):
8954 gint len = QT_UINT32 (stsd_data) - offset;
8955 const guint8 *wfex_data = stsd_data + offset;
8956 const gchar *codec_name = NULL;
8958 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
8959 /* FIXME this should also be gst_riff_strf_auds,
8960 * but the latter one is actually missing bits-per-sample :( */
8965 gint32 nSamplesPerSec;
8966 gint32 nAvgBytesPerSec;
8968 gint16 wBitsPerSample;
8973 /* FIXME: unify with similar wavformatex parsing code above */
8974 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
8980 if (QT_UINT32 (wfex_data) <= len)
8981 size = QT_UINT32 (wfex_data) - 8;
8986 /* No real data, so break out */
8989 switch (QT_FOURCC (wfex_data + 4)) {
8990 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
8992 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
8997 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
8998 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
8999 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
9000 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
9001 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
9002 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
9003 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
9005 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
9006 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
9007 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
9008 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
9009 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
9010 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
9012 if (wfex.wFormatTag == 0x0161) {
9013 codec_name = "Windows Media Audio";
9015 } else if (wfex.wFormatTag == 0x0162) {
9016 codec_name = "Windows Media Audio 9 Pro";
9018 } else if (wfex.wFormatTag == 0x0163) {
9019 codec_name = "Windows Media Audio 9 Lossless";
9020 /* is that correct? gstffmpegcodecmap.c is missing it, but
9021 * fluendo codec seems to support it */
9025 gst_caps_set_simple (stream->caps,
9026 "wmaversion", G_TYPE_INT, version,
9027 "block_align", G_TYPE_INT, wfex.nBlockAlign,
9028 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
9029 "width", G_TYPE_INT, wfex.wBitsPerSample,
9030 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
9032 if (size > wfex.cbSize) {
9035 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
9036 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
9037 size - wfex.cbSize);
9038 gst_caps_set_simple (stream->caps,
9039 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9040 gst_buffer_unref (buf);
9042 GST_WARNING_OBJECT (qtdemux, "no codec data");
9047 codec = g_strdup (codec_name);
9055 wfex_data += size + 8;
9067 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9068 GST_TAG_AUDIO_CODEC, codec, NULL);
9072 /* some bitrate info may have ended up in caps */
9073 s = gst_caps_get_structure (stream->caps, 0);
9074 gst_structure_get_int (s, "bitrate", &bitrate);
9076 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9077 GST_TAG_BITRATE, bitrate, NULL);
9080 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
9084 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
9086 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
9088 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
9092 /* If the fourcc's bottom 16 bits gives 'sm', then the top
9093 16 bits is a byte-swapped wave-style codec identifier,
9094 and we can find a WAVE header internally to a 'wave' atom here.
9095 This can more clearly be thought of as 'ms' as the top 16 bits, and a
9096 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
9099 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
9100 if (len < offset + 20) {
9101 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
9103 guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
9104 const guint8 *data = stsd_data + offset + 16;
9106 GNode *waveheadernode;
9108 wavenode = g_node_new ((guint8 *) data);
9109 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
9110 const guint8 *waveheader;
9113 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
9114 if (waveheadernode) {
9115 waveheader = (const guint8 *) waveheadernode->data;
9116 headerlen = QT_UINT32 (waveheader);
9118 if (headerlen > 8) {
9119 gst_riff_strf_auds *header = NULL;
9120 GstBuffer *headerbuf;
9126 headerbuf = gst_buffer_new_and_alloc (headerlen);
9127 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
9129 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
9130 headerbuf, &header, &extra)) {
9131 gst_caps_unref (stream->caps);
9132 /* FIXME: Need to do something with the channel reorder map */
9133 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
9134 header, extra, NULL, NULL, NULL);
9137 gst_buffer_unref (extra);
9142 GST_DEBUG ("Didn't find waveheadernode for this codec");
9144 g_node_destroy (wavenode);
9147 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
9151 /* FIXME: what is in the chunk? */
9154 gint len = QT_UINT32 (stsd_data);
9156 /* seems to be always = 116 = 0x74 */
9162 gint len = QT_UINT32 (stsd_data);
9165 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
9167 gst_buffer_fill (buf, 0, stsd_data + 0x4C, len - 0x4C);
9168 gst_caps_set_simple (stream->caps,
9169 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9170 gst_buffer_unref (buf);
9172 gst_caps_set_simple (stream->caps,
9173 "samplesize", G_TYPE_INT, samplesize, NULL);
9178 GNode *alac, *wave = NULL;
9180 /* apparently, m4a has this atom appended directly in the stsd entry,
9181 * while mov has it in a wave atom */
9182 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
9184 /* alac now refers to stsd entry atom */
9185 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
9187 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
9189 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
9192 const guint8 *alac_data = alac->data;
9193 gint len = QT_UINT32 (alac->data);
9197 GST_DEBUG_OBJECT (qtdemux,
9198 "discarding alac atom with unexpected len %d", len);
9200 /* codec-data contains alac atom size and prefix,
9201 * ffmpeg likes it that way, not quite gst-ish though ...*/
9202 buf = gst_buffer_new_and_alloc (len);
9203 gst_buffer_fill (buf, 0, alac->data, len);
9204 gst_caps_set_simple (stream->caps,
9205 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9206 gst_buffer_unref (buf);
9208 stream->bytes_per_frame = QT_UINT32 (alac_data + 12);
9209 stream->n_channels = QT_UINT8 (alac_data + 21);
9210 stream->rate = QT_UINT32 (alac_data + 32);
9213 gst_caps_set_simple (stream->caps,
9214 "samplesize", G_TYPE_INT, samplesize, NULL);
9222 gint len = QT_UINT32 (stsd_data);
9225 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
9228 gst_buffer_fill (buf, 0, stsd_data + 0x34, len - 0x34);
9230 /* If we have enough data, let's try to get the 'damr' atom. See
9231 * the 3GPP container spec (26.244) for more details. */
9232 if ((len - 0x34) > 8 &&
9233 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
9234 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9235 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
9238 gst_caps_set_simple (stream->caps,
9239 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9240 gst_buffer_unref (buf);
9246 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
9247 gint len = QT_UINT32 (stsd_data);
9250 guint16 sound_version = QT_UINT16 (stsd_data + 32);
9252 if (sound_version == 1) {
9253 guint16 channels = QT_UINT16 (stsd_data + 40);
9254 guint32 time_scale = QT_UINT32 (stsd_data + 46);
9255 guint8 codec_data[2];
9257 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
9259 gint sample_rate_index =
9260 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
9262 /* build AAC codec data */
9263 codec_data[0] = profile << 3;
9264 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
9265 codec_data[1] = (sample_rate_index & 0x01) << 7;
9266 codec_data[1] |= (channels & 0xF) << 3;
9268 buf = gst_buffer_new_and_alloc (2);
9269 gst_buffer_fill (buf, 0, codec_data, 2);
9270 gst_caps_set_simple (stream->caps,
9271 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9272 gst_buffer_unref (buf);
9278 GST_INFO_OBJECT (qtdemux,
9279 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
9283 GST_INFO_OBJECT (qtdemux,
9284 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
9285 GST_FOURCC_ARGS (fourcc), stream->caps);
9287 } else if (stream->subtype == FOURCC_strm) {
9288 if (fourcc == FOURCC_rtsp) {
9289 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
9291 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
9292 GST_FOURCC_ARGS (fourcc));
9293 goto unknown_stream;
9295 stream->sampled = TRUE;
9296 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
9297 || stream->subtype == FOURCC_sbtl) {
9299 stream->sampled = TRUE;
9300 stream->sparse = TRUE;
9303 qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
9305 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9306 GST_TAG_SUBTITLE_CODEC, codec, NULL);
9311 /* hunt for sort-of codec data */
9318 /* look for palette in a stsd->mp4s->esds sub-atom */
9319 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
9321 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
9324 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
9328 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
9332 GST_INFO_OBJECT (qtdemux,
9333 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
9336 GST_INFO_OBJECT (qtdemux,
9337 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
9338 GST_FOURCC_ARGS (fourcc), stream->caps);
9340 /* everything in 1 sample */
9341 stream->sampled = TRUE;
9344 qtdemux_generic_caps (qtdemux, stream, fourcc, stsd_data, &codec);
9346 if (stream->caps == NULL)
9347 goto unknown_stream;
9350 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9351 GST_TAG_SUBTITLE_CODEC, codec, NULL);
9357 /* promote to sampled format */
9358 if (stream->fourcc == FOURCC_samr) {
9359 /* force mono 8000 Hz for AMR */
9360 stream->sampled = TRUE;
9361 stream->n_channels = 1;
9362 stream->rate = 8000;
9363 } else if (stream->fourcc == FOURCC_sawb) {
9364 /* force mono 16000 Hz for AMR-WB */
9365 stream->sampled = TRUE;
9366 stream->n_channels = 1;
9367 stream->rate = 16000;
9368 } else if (stream->fourcc == FOURCC_mp4a) {
9369 stream->sampled = TRUE;
9372 /* collect sample information */
9373 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
9374 goto samples_failed;
9376 if (qtdemux->fragmented) {
9380 /* need all moov samples as basis; probably not many if any at all */
9381 /* prevent moof parsing taking of at this time */
9382 offset = qtdemux->moof_offset;
9383 qtdemux->moof_offset = 0;
9384 if (stream->n_samples &&
9385 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
9386 qtdemux->moof_offset = offset;
9387 goto samples_failed;
9389 qtdemux->moof_offset = 0;
9390 /* movie duration more reliable in this case (e.g. mehd) */
9391 if (qtdemux->segment.duration &&
9392 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
9394 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
9395 /* need defaults for fragments */
9396 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
9399 /* configure segments */
9400 if (!qtdemux_parse_segments (qtdemux, stream, trak))
9401 goto segments_failed;
9403 /* add some language tag, if useful */
9404 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
9405 strcmp (stream->lang_id, "und")) {
9406 const gchar *lang_code;
9408 /* convert ISO 639-2 code to ISO 639-1 */
9409 lang_code = gst_tag_get_language_code (stream->lang_id);
9410 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9411 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
9414 /* Check for UDTA tags */
9415 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
9416 qtdemux_parse_udta (qtdemux, stream->pending_tags, udta);
9419 /* now we are ready to add the stream */
9420 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
9421 goto too_many_streams;
9423 if (!qtdemux->got_moov) {
9424 qtdemux->streams[qtdemux->n_streams] = stream;
9425 qtdemux->n_streams++;
9426 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
9434 GST_INFO_OBJECT (qtdemux, "skip disabled track");
9436 gst_qtdemux_stream_free (qtdemux, stream);
9441 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9442 (_("This file is corrupt and cannot be played.")), (NULL));
9444 gst_qtdemux_stream_free (qtdemux, stream);
9449 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
9451 gst_qtdemux_stream_free (qtdemux, stream);
9457 /* we posted an error already */
9458 /* free stbl sub-atoms */
9459 gst_qtdemux_stbl_free (stream);
9461 gst_qtdemux_stream_free (qtdemux, stream);
9466 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
9469 gst_qtdemux_stream_free (qtdemux, stream);
9474 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
9475 GST_FOURCC_ARGS (stream->subtype));
9477 gst_qtdemux_stream_free (qtdemux, stream);
9482 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
9483 (_("This file contains too many streams. Only playing first %d"),
9484 GST_QTDEMUX_MAX_STREAMS), (NULL));
9489 /* If we can estimate the overall bitrate, and don't have information about the
9490 * stream bitrate for exactly one stream, this guesses the stream bitrate as
9491 * the overall bitrate minus the sum of the bitrates of all other streams. This
9492 * should be useful for the common case where we have one audio and one video
9493 * stream and can estimate the bitrate of one, but not the other. */
9495 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
9497 QtDemuxStream *stream = NULL;
9498 gint64 size, sys_bitrate, sum_bitrate = 0;
9499 GstClockTime duration;
9503 if (qtdemux->fragmented)
9506 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
9508 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
9510 GST_DEBUG_OBJECT (qtdemux,
9511 "Size in bytes of the stream not known - bailing");
9515 /* Subtract the header size */
9516 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
9517 size, qtdemux->header_size);
9519 if (size < qtdemux->header_size)
9522 size = size - qtdemux->header_size;
9524 if (!gst_qtdemux_get_duration (qtdemux, &duration) ||
9525 duration == GST_CLOCK_TIME_NONE) {
9526 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
9530 for (i = 0; i < qtdemux->n_streams; i++) {
9531 switch (qtdemux->streams[i]->subtype) {
9534 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
9535 qtdemux->streams[i]->caps);
9536 /* retrieve bitrate, prefer avg then max */
9538 if (qtdemux->streams[i]->pending_tags) {
9539 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
9540 GST_TAG_MAXIMUM_BITRATE, &bitrate);
9541 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
9542 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
9543 GST_TAG_NOMINAL_BITRATE, &bitrate);
9544 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
9545 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
9546 GST_TAG_BITRATE, &bitrate);
9547 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
9550 sum_bitrate += bitrate;
9553 GST_DEBUG_OBJECT (qtdemux,
9554 ">1 stream with unknown bitrate - bailing");
9557 stream = qtdemux->streams[i];
9561 /* For other subtypes, we assume no significant impact on bitrate */
9567 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
9571 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
9573 if (sys_bitrate < sum_bitrate) {
9574 /* This can happen, since sum_bitrate might be derived from maximum
9575 * bitrates and not average bitrates */
9576 GST_DEBUG_OBJECT (qtdemux,
9577 "System bitrate less than sum bitrate - bailing");
9581 bitrate = sys_bitrate - sum_bitrate;
9582 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
9583 ", Stream bitrate = %u", sys_bitrate, bitrate);
9585 if (!stream->pending_tags)
9586 stream->pending_tags = gst_tag_list_new_empty ();
9588 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9589 GST_TAG_BITRATE, bitrate, NULL);
9592 static GstFlowReturn
9593 qtdemux_prepare_streams (GstQTDemux * qtdemux)
9596 GstFlowReturn ret = GST_FLOW_OK;
9598 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
9600 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
9601 QtDemuxStream *stream = qtdemux->streams[i];
9602 guint32 sample_num = 0;
9604 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
9605 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
9607 if (qtdemux->fragmented) {
9608 /* need all moov samples first */
9609 GST_OBJECT_LOCK (qtdemux);
9610 while (stream->n_samples == 0)
9611 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
9613 GST_OBJECT_UNLOCK (qtdemux);
9615 /* discard any stray moof */
9616 qtdemux->moof_offset = 0;
9619 /* prepare braking */
9620 if (ret != GST_FLOW_ERROR)
9623 /* in pull mode, we should have parsed some sample info by now;
9624 * and quite some code will not handle no samples.
9625 * in push mode, we'll just have to deal with it */
9626 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
9627 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
9628 gst_qtdemux_remove_stream (qtdemux, i);
9633 /* parse the initial sample for use in setting the frame rate cap */
9634 while (sample_num == 0 && sample_num < stream->n_samples) {
9635 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
9639 if (stream->n_samples > 0 && stream->stbl_index >= 0) {
9640 stream->first_duration = stream->samples[0].duration;
9641 GST_LOG_OBJECT (qtdemux, "stream %d first duration %u",
9642 stream->track_id, stream->first_duration);
9649 static GstFlowReturn
9650 qtdemux_expose_streams (GstQTDemux * qtdemux)
9653 GstFlowReturn ret = GST_FLOW_OK;
9654 GSList *oldpads = NULL;
9657 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
9659 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
9660 QtDemuxStream *stream = qtdemux->streams[i];
9661 GstPad *oldpad = stream->pad;
9664 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
9665 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
9667 if ((stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl) &&
9668 stream->track_id == qtdemux->chapters_track_id) {
9669 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
9670 so that it doesn't look like a subtitle track */
9671 gst_qtdemux_remove_stream (qtdemux, i);
9676 /* now we have all info and can expose */
9677 list = stream->pending_tags;
9678 stream->pending_tags = NULL;
9680 oldpads = g_slist_prepend (oldpads, oldpad);
9681 gst_qtdemux_add_stream (qtdemux, stream, list);
9684 gst_qtdemux_guess_bitrate (qtdemux);
9686 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
9688 for (iter = oldpads; iter; iter = g_slist_next (iter)) {
9689 GstPad *oldpad = iter->data;
9691 gst_pad_push_event (oldpad, gst_event_new_eos ());
9692 gst_pad_set_active (oldpad, FALSE);
9693 gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
9694 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, oldpad);
9695 gst_object_unref (oldpad);
9698 /* check if we should post a redirect in case there is a single trak
9699 * and it is a redirecting trak */
9700 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
9703 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
9704 "an external content");
9705 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
9706 gst_structure_new ("redirect",
9707 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
9709 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
9710 qtdemux->posted_redirect = TRUE;
9713 for (i = 0; i < qtdemux->n_streams; i++) {
9714 QtDemuxStream *stream = qtdemux->streams[i];
9716 qtdemux_do_allocation (qtdemux, stream);
9719 qtdemux->exposed = TRUE;
9723 /* check if major or compatible brand is 3GP */
9724 static inline gboolean
9725 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
9728 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
9729 GST_MAKE_FOURCC ('3', 'g', 0, 0));
9730 } else if (qtdemux->comp_brands != NULL) {
9734 gboolean res = FALSE;
9736 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
9740 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
9741 GST_MAKE_FOURCC ('3', 'g', 0, 0));
9745 gst_buffer_unmap (qtdemux->comp_brands, &map);
9752 /* check if tag is a spec'ed 3GP tag keyword storing a string */
9753 static inline gboolean
9754 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
9756 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
9757 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
9758 || fourcc == FOURCC_albm;
9762 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
9763 const char *tag, const char *dummy, GNode * node)
9765 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
9769 gdouble longitude, latitude, altitude;
9772 len = QT_UINT32 (node->data);
9779 /* TODO: language code skipped */
9781 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
9784 /* do not alarm in trivial case, but bail out otherwise */
9785 if (*(data + offset) != 0) {
9786 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
9790 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
9791 GST_TAG_GEO_LOCATION_NAME, name, NULL);
9792 offset += strlen (name);
9796 if (len < offset + 2 + 4 + 4 + 4)
9799 /* +1 +1 = skip null-terminator and location role byte */
9801 /* table in spec says unsigned, semantics say negative has meaning ... */
9802 longitude = QT_SFP32 (data + offset);
9805 latitude = QT_SFP32 (data + offset);
9808 altitude = QT_SFP32 (data + offset);
9810 /* one invalid means all are invalid */
9811 if (longitude >= -180.0 && longitude <= 180.0 &&
9812 latitude >= -90.0 && latitude <= 90.0) {
9813 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
9814 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
9815 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
9816 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
9819 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
9826 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
9833 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
9834 const char *tag, const char *dummy, GNode * node)
9840 len = QT_UINT32 (node->data);
9844 y = QT_UINT16 ((guint8 *) node->data + 12);
9846 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
9849 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
9851 date = g_date_new_dmy (1, 1, y);
9852 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
9857 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
9858 const char *tag, const char *dummy, GNode * node)
9861 char *tag_str = NULL;
9866 len = QT_UINT32 (node->data);
9871 entity = (guint8 *) node->data + offset;
9872 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
9873 GST_DEBUG_OBJECT (qtdemux,
9874 "classification info: %c%c%c%c invalid classification entity",
9875 entity[0], entity[1], entity[2], entity[3]);
9880 table = QT_UINT16 ((guint8 *) node->data + offset);
9882 /* Language code skipped */
9886 /* Tag format: "XXXX://Y[YYYY]/classification info string"
9887 * XXXX: classification entity, fixed length 4 chars.
9888 * Y[YYYY]: classification table, max 5 chars.
9890 tag_str = g_strdup_printf ("----://%u/%s",
9891 table, (char *) node->data + offset);
9893 /* memcpy To be sure we're preserving byte order */
9894 memcpy (tag_str, entity, 4);
9895 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
9897 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
9906 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
9912 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
9913 const char *tag, const char *dummy, GNode * node)
9915 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
9921 gboolean ret = TRUE;
9922 const gchar *charset = NULL;
9924 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9926 len = QT_UINT32 (data->data);
9927 type = QT_UINT32 ((guint8 *) data->data + 8);
9928 if (type == 0x00000001 && len > 16) {
9929 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
9932 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
9933 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
9936 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
9940 len = QT_UINT32 (node->data);
9941 type = QT_UINT32 ((guint8 *) node->data + 4);
9942 if ((type >> 24) == 0xa9) {
9946 /* Type starts with the (C) symbol, so the next data is a list
9947 * of (string size(16), language code(16), string) */
9949 str_len = QT_UINT16 ((guint8 *) node->data + 8);
9950 lang_code = QT_UINT16 ((guint8 *) node->data + 10);
9952 /* the string + fourcc + size + 2 16bit fields,
9953 * means that there are more tags in this atom */
9954 if (len > str_len + 8 + 4) {
9955 /* TODO how to represent the same tag in different languages? */
9956 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
9957 "text alternatives, reading only first one");
9961 len = str_len + 8 + 4; /* remove trailing strings that we don't use */
9962 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
9964 if (lang_code < 0x800) { /* MAC encoded string */
9967 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
9968 QT_FOURCC ((guint8 *) node->data + 4))) {
9969 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
9971 /* we go for 3GP style encoding if major brands claims so,
9972 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
9973 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
9974 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
9975 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
9977 /* 16-bit Language code is ignored here as well */
9978 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
9985 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
9986 ret = FALSE; /* may have to fallback */
9991 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
9992 charset, NULL, NULL, &err);
9994 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
9995 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
10000 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
10001 len - offset, env_vars);
10004 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
10005 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
10009 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
10016 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
10017 const char *tag, const char *dummy, GNode * node)
10019 qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
10023 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
10024 const char *tag, const char *dummy, GNode * node)
10026 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
10028 char *s, *t, *k = NULL;
10033 /* first try normal string tag if major brand not 3GP */
10034 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
10035 if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
10036 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
10037 * let's try it 3gpp way after minor safety check */
10039 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
10045 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
10049 len = QT_UINT32 (data);
10053 count = QT_UINT8 (data + 14);
10055 for (; count; count--) {
10058 if (offset + 1 > len)
10060 slen = QT_UINT8 (data + offset);
10062 if (offset + slen > len)
10064 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
10067 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
10069 t = g_strjoin (",", k, s, NULL);
10077 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
10084 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
10085 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
10094 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
10100 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
10101 const char *tag1, const char *tag2, GNode * node)
10108 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
10110 len = QT_UINT32 (data->data);
10111 type = QT_UINT32 ((guint8 *) data->data + 8);
10112 if (type == 0x00000000 && len >= 22) {
10113 n1 = QT_UINT16 ((guint8 *) data->data + 18);
10114 n2 = QT_UINT16 ((guint8 *) data->data + 20);
10116 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
10117 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
10120 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
10121 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
10128 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
10129 const char *tag1, const char *dummy, GNode * node)
10136 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
10138 len = QT_UINT32 (data->data);
10139 type = QT_UINT32 ((guint8 *) data->data + 8);
10140 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
10141 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
10142 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
10143 n1 = QT_UINT16 ((guint8 *) data->data + 16);
10145 /* do not add bpm=0 */
10146 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
10147 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
10155 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
10156 const char *tag1, const char *dummy, GNode * node)
10163 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
10165 len = QT_UINT32 (data->data);
10166 type = QT_UINT32 ((guint8 *) data->data + 8);
10167 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
10168 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
10169 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
10170 num = QT_UINT32 ((guint8 *) data->data + 16);
10172 /* do not add num=0 */
10173 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
10174 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
10181 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
10182 const char *tag1, const char *dummy, GNode * node)
10189 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
10191 len = QT_UINT32 (data->data);
10192 type = QT_UINT32 ((guint8 *) data->data + 8);
10193 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
10194 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
10196 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
10197 len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
10198 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
10199 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
10200 gst_sample_unref (sample);
10207 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
10208 const char *tag, const char *dummy, GNode * node)
10215 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
10217 len = QT_UINT32 (data->data);
10218 type = QT_UINT32 ((guint8 *) data->data + 8);
10219 if (type == 0x00000001 && len > 16) {
10220 guint y, m = 1, d = 1;
10223 s = g_strndup ((char *) data->data + 16, len - 16);
10224 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
10225 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
10226 if (ret >= 1 && y > 1500 && y < 3000) {
10229 date = g_date_new_dmy (d, m, y);
10230 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
10231 g_date_free (date);
10233 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
10241 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
10242 const char *tag, const char *dummy, GNode * node)
10246 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
10248 /* re-route to normal string tag if major brand says so
10249 * or no data atom and compatible brand suggests so */
10250 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
10251 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
10252 qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
10257 guint len, type, n;
10259 len = QT_UINT32 (data->data);
10260 type = QT_UINT32 ((guint8 *) data->data + 8);
10261 if (type == 0x00000000 && len >= 18) {
10262 n = QT_UINT16 ((guint8 *) data->data + 16);
10264 const gchar *genre;
10266 genre = gst_tag_id3_genre_get (n - 1);
10267 if (genre != NULL) {
10268 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
10269 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
10277 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
10278 const gchar * tag, guint8 * data, guint32 datasize)
10283 /* make a copy to have \0 at the end */
10284 datacopy = g_strndup ((gchar *) data, datasize);
10286 /* convert the str to double */
10287 if (sscanf (datacopy, "%lf", &value) == 1) {
10288 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
10289 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
10291 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
10299 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
10300 const char *tag, const char *tag_bis, GNode * node)
10309 const gchar *meanstr;
10310 const gchar *namestr;
10312 /* checking the whole ---- atom size for consistency */
10313 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
10314 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
10318 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
10320 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
10324 meansize = QT_UINT32 (mean->data);
10325 if (meansize <= 12) {
10326 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
10329 meanstr = ((gchar *) mean->data) + 12;
10332 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
10334 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
10338 namesize = QT_UINT32 (name->data);
10339 if (namesize <= 12) {
10340 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
10343 namestr = ((gchar *) name->data) + 12;
10351 * uint24 - data type
10355 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
10357 GST_WARNING_OBJECT (demux, "No data atom in this tag");
10360 datasize = QT_UINT32 (data->data);
10361 if (datasize <= 16) {
10362 GST_WARNING_OBJECT (demux, "Data atom too small");
10365 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
10367 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
10368 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
10369 static const struct
10371 const gchar name[28];
10372 const gchar tag[28];
10375 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
10376 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
10377 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
10378 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
10379 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
10380 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
10381 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
10382 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
10386 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
10387 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
10388 switch (gst_tag_get_type (tags[i].tag)) {
10389 case G_TYPE_DOUBLE:
10390 qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
10391 ((guint8 *) data->data) + 16, datasize - 16);
10393 case G_TYPE_STRING:
10394 qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
10403 if (i == G_N_ELEMENTS (tags))
10413 #ifndef GST_DISABLE_GST_DEBUG
10415 gchar *namestr_dbg;
10416 gchar *meanstr_dbg;
10418 meanstr_dbg = g_strndup (meanstr, meansize);
10419 namestr_dbg = g_strndup (namestr, namesize);
10421 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
10422 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
10424 g_free (namestr_dbg);
10425 g_free (meanstr_dbg);
10432 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
10433 const char *tag_bis, GNode * node)
10438 GstTagList *id32_taglist = NULL;
10440 GST_LOG_OBJECT (demux, "parsing ID32");
10443 len = GST_READ_UINT32_BE (data);
10445 /* need at least full box and language tag */
10449 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
10450 gst_buffer_fill (buf, 0, data + 14, len - 14);
10452 id32_taglist = gst_tag_list_from_id3v2_tag (buf);
10453 if (id32_taglist) {
10454 GST_LOG_OBJECT (demux, "parsing ok");
10455 gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
10456 gst_tag_list_unref (id32_taglist);
10458 GST_LOG_OBJECT (demux, "parsing failed");
10461 gst_buffer_unref (buf);
10464 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
10465 const char *tag, const char *tag_bis, GNode * node);
10468 FOURCC_pcst -> if media is a podcast -> bool
10469 FOURCC_cpil -> if media is part of a compilation -> bool
10470 FOURCC_pgap -> if media is part of a gapless context -> bool
10471 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
10474 static const struct
10477 const gchar *gst_tag;
10478 const gchar *gst_tag_bis;
10479 const GstQTDemuxAddTagFunc func;
10482 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
10483 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
10484 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
10485 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
10486 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
10487 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
10488 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
10489 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
10490 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
10491 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
10492 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
10493 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
10494 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
10495 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
10496 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
10497 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
10498 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
10499 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
10500 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
10501 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
10502 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
10503 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
10504 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
10505 qtdemux_tag_add_num}, {
10506 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
10507 qtdemux_tag_add_num}, {
10508 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
10509 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
10510 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
10511 FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
10512 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
10513 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
10514 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
10515 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
10516 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
10517 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
10518 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
10519 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
10520 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
10521 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
10522 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
10523 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
10524 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
10525 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
10526 qtdemux_tag_add_classification}, {
10527 FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
10528 FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
10529 FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
10531 /* This is a special case, some tags are stored in this
10532 * 'reverse dns naming', according to:
10533 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
10536 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
10537 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
10538 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
10541 struct _GstQtDemuxTagList
10544 GstTagList *taglist;
10546 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
10549 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
10555 const gchar *style;
10560 GstQTDemux *demux = qtdemuxtaglist->demux;
10561 GstTagList *taglist = qtdemuxtaglist->taglist;
10564 len = QT_UINT32 (data);
10565 buf = gst_buffer_new_and_alloc (len);
10566 gst_buffer_fill (buf, 0, data, len);
10568 /* heuristic to determine style of tag */
10569 if (QT_FOURCC (data + 4) == FOURCC_____ ||
10570 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
10572 else if (demux->major_brand == FOURCC_qt__)
10573 style = "quicktime";
10574 /* fall back to assuming iso/3gp tag style */
10578 /* santize the name for the caps. */
10579 for (i = 0; i < 4; i++) {
10580 guint8 d = data[4 + i];
10581 if (g_ascii_isalnum (d))
10582 ndata[i] = g_ascii_tolower (d);
10587 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
10588 ndata[0], ndata[1], ndata[2], ndata[3]);
10589 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
10591 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
10592 sample = gst_sample_new (buf, NULL, NULL, s);
10593 gst_buffer_unref (buf);
10594 g_free (media_type);
10596 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
10599 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
10600 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
10602 gst_sample_unref (sample);
10606 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
10613 GstQtDemuxTagList demuxtaglist;
10615 demuxtaglist.demux = qtdemux;
10616 demuxtaglist.taglist = taglist;
10618 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
10619 if (meta != NULL) {
10620 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
10621 if (ilst == NULL) {
10622 GST_LOG_OBJECT (qtdemux, "no ilst");
10627 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
10631 while (i < G_N_ELEMENTS (add_funcs)) {
10632 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
10636 len = QT_UINT32 (node->data);
10638 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
10639 GST_FOURCC_ARGS (add_funcs[i].fourcc));
10641 add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
10642 add_funcs[i].gst_tag_bis, node);
10644 g_node_destroy (node);
10650 /* parsed nodes have been removed, pass along remainder as blob */
10651 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
10652 (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
10654 /* parse up XMP_ node if existing */
10655 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
10656 if (xmp_ != NULL) {
10658 GstTagList *xmptaglist;
10660 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
10661 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
10662 xmptaglist = gst_tag_list_from_xmp_buffer (buf);
10663 gst_buffer_unref (buf);
10665 qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
10667 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
10673 GstStructure *structure; /* helper for sort function */
10675 guint min_req_bitrate;
10676 guint min_req_qt_version;
10680 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
10682 GstQtReference *ref_a = (GstQtReference *) a;
10683 GstQtReference *ref_b = (GstQtReference *) b;
10685 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
10686 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
10688 /* known bitrates go before unknown; higher bitrates go first */
10689 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
10692 /* sort the redirects and post a message for the application.
10695 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
10697 GstQtReference *best;
10700 GValue list_val = { 0, };
10703 g_assert (references != NULL);
10705 references = g_list_sort (references, qtdemux_redirects_sort_func);
10707 best = (GstQtReference *) references->data;
10709 g_value_init (&list_val, GST_TYPE_LIST);
10711 for (l = references; l != NULL; l = l->next) {
10712 GstQtReference *ref = (GstQtReference *) l->data;
10713 GValue struct_val = { 0, };
10715 ref->structure = gst_structure_new ("redirect",
10716 "new-location", G_TYPE_STRING, ref->location, NULL);
10718 if (ref->min_req_bitrate > 0) {
10719 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
10720 ref->min_req_bitrate, NULL);
10723 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
10724 g_value_set_boxed (&struct_val, ref->structure);
10725 gst_value_list_append_value (&list_val, &struct_val);
10726 g_value_unset (&struct_val);
10727 /* don't free anything here yet, since we need best->structure below */
10730 g_assert (best != NULL);
10731 s = gst_structure_copy (best->structure);
10733 if (g_list_length (references) > 1) {
10734 gst_structure_set_value (s, "locations", &list_val);
10737 g_value_unset (&list_val);
10739 for (l = references; l != NULL; l = l->next) {
10740 GstQtReference *ref = (GstQtReference *) l->data;
10742 gst_structure_free (ref->structure);
10743 g_free (ref->location);
10746 g_list_free (references);
10748 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
10749 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
10750 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
10751 qtdemux->posted_redirect = TRUE;
10754 /* look for redirect nodes, collect all redirect information and
10758 qtdemux_parse_redirects (GstQTDemux * qtdemux)
10760 GNode *rmra, *rmda, *rdrf;
10762 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
10764 GList *redirects = NULL;
10766 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
10768 GstQtReference ref = { NULL, NULL, 0, 0 };
10769 GNode *rmdr, *rmvc;
10771 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
10772 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
10773 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
10774 ref.min_req_bitrate);
10777 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
10778 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
10779 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
10781 #ifndef GST_DISABLE_GST_DEBUG
10782 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
10784 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
10786 GST_LOG_OBJECT (qtdemux,
10787 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
10788 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
10789 bitmask, check_type);
10790 if (package == FOURCC_qtim && check_type == 0) {
10791 ref.min_req_qt_version = version;
10795 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
10801 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
10802 if (ref_len > 20) {
10803 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
10804 ref_data = (guint8 *) rdrf->data + 20;
10805 if (ref_type == FOURCC_alis) {
10806 guint record_len, record_version, fn_len;
10808 if (ref_len > 70) {
10809 /* MacOSX alias record, google for alias-layout.txt */
10810 record_len = QT_UINT16 (ref_data + 4);
10811 record_version = QT_UINT16 (ref_data + 4 + 2);
10812 fn_len = QT_UINT8 (ref_data + 50);
10813 if (record_len > 50 && record_version == 2 && fn_len > 0) {
10814 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
10817 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
10820 } else if (ref_type == FOURCC_url_) {
10821 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
10823 GST_DEBUG_OBJECT (qtdemux,
10824 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
10825 GST_FOURCC_ARGS (ref_type));
10827 if (ref.location != NULL) {
10828 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
10830 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
10832 GST_WARNING_OBJECT (qtdemux,
10833 "Failed to extract redirect location from rdrf atom");
10836 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
10840 /* look for others */
10841 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
10844 if (redirects != NULL) {
10845 qtdemux_process_redirects (qtdemux, redirects);
10851 static GstTagList *
10852 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
10856 if (tags == NULL) {
10857 tags = gst_tag_list_new_empty ();
10858 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
10861 if (qtdemux->major_brand == FOURCC_mjp2)
10862 fmt = "Motion JPEG 2000";
10863 else if ((qtdemux->major_brand & 0xffff) == GST_MAKE_FOURCC ('3', 'g', 0, 0))
10865 else if (qtdemux->major_brand == FOURCC_qt__)
10867 else if (qtdemux->fragmented)
10870 fmt = "ISO MP4/M4A";
10872 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
10873 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
10875 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
10881 /* we have read th complete moov node now.
10882 * This function parses all of the relevant info, creates the traks and
10883 * prepares all data structures for playback
10886 qtdemux_parse_tree (GstQTDemux * qtdemux)
10892 GstClockTime duration;
10893 guint64 creation_time;
10894 GstDateTime *datetime = NULL;
10897 /* make sure we have a usable taglist */
10898 if (!qtdemux->tag_list) {
10899 qtdemux->tag_list = gst_tag_list_new_empty ();
10900 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
10902 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
10905 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
10906 if (mvhd == NULL) {
10907 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
10908 return qtdemux_parse_redirects (qtdemux);
10911 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
10912 if (version == 1) {
10913 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
10914 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
10915 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
10916 } else if (version == 0) {
10917 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
10918 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
10919 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
10921 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
10925 /* Moving qt creation time (secs since 1904) to unix time */
10926 if (creation_time != 0) {
10927 /* Try to use epoch first as it should be faster and more commonly found */
10928 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
10931 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
10932 /* some data cleansing sanity */
10933 g_get_current_time (&now);
10934 if (now.tv_sec + 24 * 3600 < creation_time) {
10935 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
10937 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
10940 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
10941 GDateTime *dt, *dt_local;
10943 dt = g_date_time_add_seconds (base_dt, creation_time);
10944 dt_local = g_date_time_to_local (dt);
10945 datetime = gst_date_time_new_from_g_date_time (dt_local);
10947 g_date_time_unref (base_dt);
10948 g_date_time_unref (dt);
10952 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
10953 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
10955 gst_date_time_unref (datetime);
10958 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
10959 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
10961 /* check for fragmented file and get some (default) data */
10962 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
10965 GstByteReader mehd_data;
10967 /* let track parsing or anyone know weird stuff might happen ... */
10968 qtdemux->fragmented = TRUE;
10970 /* compensate for total duration */
10971 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
10973 qtdemux_parse_mehd (qtdemux, &mehd_data);
10976 /* set duration in the segment info */
10977 gst_qtdemux_get_duration (qtdemux, &duration);
10979 qtdemux->segment.duration = duration;
10980 /* also do not exceed duration; stop is set that way post seek anyway,
10981 * and segment activation falls back to duration,
10982 * whereas loop only checks stop, so let's align this here as well */
10983 qtdemux->segment.stop = duration;
10986 /* parse all traks */
10987 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
10989 qtdemux_parse_trak (qtdemux, trak);
10990 /* iterate all siblings */
10991 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
10994 if (!qtdemux->tag_list) {
10995 GST_DEBUG_OBJECT (qtdemux, "new tag list");
10996 qtdemux->tag_list = gst_tag_list_new_empty ();
10997 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
10999 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
11003 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
11005 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
11007 GST_LOG_OBJECT (qtdemux, "No udta node found.");
11010 /* maybe also some tags in meta box */
11011 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
11013 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
11014 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
11016 GST_LOG_OBJECT (qtdemux, "No meta node found.");
11019 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
11024 /* taken from ffmpeg */
11026 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
11038 len = (len << 7) | (c & 0x7f);
11046 /* this can change the codec originally present in @list */
11048 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
11049 GNode * esds, GstTagList * list)
11051 int len = QT_UINT32 (esds->data);
11052 guint8 *ptr = esds->data;
11053 guint8 *end = ptr + len;
11055 guint8 *data_ptr = NULL;
11057 guint8 object_type_id = 0;
11058 const char *codec_name = NULL;
11059 GstCaps *caps = NULL;
11061 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
11063 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
11065 while (ptr + 1 < end) {
11066 tag = QT_UINT8 (ptr);
11067 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
11069 len = read_descr_size (ptr, end, &ptr);
11070 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
11072 /* Check the stated amount of data is available for reading */
11073 if (len < 0 || ptr + len > end)
11077 case ES_DESCRIPTOR_TAG:
11078 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
11079 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
11082 case DECODER_CONFIG_DESC_TAG:{
11083 guint max_bitrate, avg_bitrate;
11085 object_type_id = QT_UINT8 (ptr);
11086 max_bitrate = QT_UINT32 (ptr + 5);
11087 avg_bitrate = QT_UINT32 (ptr + 9);
11088 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
11089 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
11090 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
11091 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
11092 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
11093 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
11094 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
11095 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
11097 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
11098 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
11099 avg_bitrate, NULL);
11104 case DECODER_SPECIFIC_INFO_TAG:
11105 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
11106 if (object_type_id == 0xe0 && len == 0x40) {
11112 GST_DEBUG_OBJECT (qtdemux,
11113 "Have VOBSUB palette. Creating palette event");
11114 /* move to decConfigDescr data and read palette */
11116 for (i = 0; i < 16; i++) {
11117 clut[i] = QT_UINT32 (data);
11121 s = gst_structure_new ("application/x-gst-dvd", "event",
11122 G_TYPE_STRING, "dvd-spu-clut-change",
11123 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
11124 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
11125 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
11126 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
11127 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
11128 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
11129 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
11130 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
11133 /* store event and trigger custom processing */
11134 stream->pending_event =
11135 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
11137 /* Generic codec_data handler puts it on the caps */
11144 case SL_CONFIG_DESC_TAG:
11145 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
11149 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
11151 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
11157 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
11158 * in use, and should also be used to override some other parameters for some
11160 switch (object_type_id) {
11161 case 0x20: /* MPEG-4 */
11162 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
11163 * profile_and_level_indication */
11164 if (data_ptr != NULL && data_len >= 5 &&
11165 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
11166 gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
11167 data_ptr + 4, data_len - 4);
11169 break; /* Nothing special needed here */
11170 case 0x21: /* H.264 */
11171 codec_name = "H.264 / AVC";
11172 caps = gst_caps_new_simple ("video/x-h264",
11173 "stream-format", G_TYPE_STRING, "avc",
11174 "alignment", G_TYPE_STRING, "au", NULL);
11176 case 0x40: /* AAC (any) */
11177 case 0x66: /* AAC Main */
11178 case 0x67: /* AAC LC */
11179 case 0x68: /* AAC SSR */
11180 /* Override channels and rate based on the codec_data, as it's often
11182 /* Only do so for basic setup without HE-AAC extension */
11183 if (data_ptr && data_len == 2) {
11184 guint channels, rateindex, rate;
11186 /* FIXME: add gst_codec_utils_aac_get_{channels|sample_rate}()? */
11187 channels = (data_ptr[1] & 0x7f) >> 3;
11188 if (channels > 0 && channels < 7) {
11189 stream->n_channels = channels;
11190 } else if (channels == 7) {
11191 stream->n_channels = 8;
11194 rateindex = ((data_ptr[0] & 0x7) << 1) | ((data_ptr[1] & 0x80) >> 7);
11195 rate = gst_codec_utils_aac_get_sample_rate_from_index (rateindex);
11197 stream->rate = rate;
11200 /* Set level and profile if possible */
11201 if (data_ptr != NULL && data_len >= 2) {
11202 gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
11203 data_ptr, data_len);
11206 case 0x60: /* MPEG-2, various profiles */
11212 codec_name = "MPEG-2 video";
11213 caps = gst_caps_new_simple ("video/mpeg",
11214 "mpegversion", G_TYPE_INT, 2,
11215 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11217 case 0x69: /* MPEG-2 BC audio */
11218 case 0x6B: /* MPEG-1 audio */
11219 caps = gst_caps_new_simple ("audio/mpeg",
11220 "mpegversion", G_TYPE_INT, 1, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
11221 codec_name = "MPEG-1 audio";
11223 case 0x6A: /* MPEG-1 */
11224 codec_name = "MPEG-1 video";
11225 caps = gst_caps_new_simple ("video/mpeg",
11226 "mpegversion", G_TYPE_INT, 1,
11227 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11229 case 0x6C: /* MJPEG */
11231 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
11233 codec_name = "Motion-JPEG";
11235 case 0x6D: /* PNG */
11237 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
11239 codec_name = "PNG still images";
11241 case 0x6E: /* JPEG2000 */
11242 codec_name = "JPEG-2000";
11243 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
11245 case 0xA4: /* Dirac */
11246 codec_name = "Dirac";
11247 caps = gst_caps_new_empty_simple ("video/x-dirac");
11249 case 0xA5: /* AC3 */
11250 codec_name = "AC-3 audio";
11251 caps = gst_caps_new_simple ("audio/x-ac3",
11252 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
11254 case 0xA9: /* AC3 */
11255 codec_name = "DTS audio";
11256 caps = gst_caps_new_simple ("audio/x-dts",
11257 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
11259 case 0xE1: /* QCELP */
11260 /* QCELP, the codec_data is a riff tag (little endian) with
11261 * 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). */
11262 caps = gst_caps_new_empty_simple ("audio/qcelp");
11263 codec_name = "QCELP";
11269 /* If we have a replacement caps, then change our caps for this stream */
11271 gst_caps_unref (stream->caps);
11272 stream->caps = caps;
11275 if (codec_name && list)
11276 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
11277 GST_TAG_AUDIO_CODEC, codec_name, NULL);
11279 /* Add the codec_data attribute to caps, if we have it */
11283 buffer = gst_buffer_new_and_alloc (data_len);
11284 gst_buffer_fill (buffer, 0, data_ptr, data_len);
11286 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
11287 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
11289 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
11291 gst_buffer_unref (buffer);
11296 #define _codec(name) \
11298 if (codec_name) { \
11299 *codec_name = g_strdup (name); \
11304 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
11305 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
11307 GstCaps *caps = NULL;
11308 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
11311 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
11312 _codec ("PNG still images");
11313 caps = gst_caps_new_empty_simple ("image/png");
11315 case GST_MAKE_FOURCC ('j', 'p', 'e', 'g'):
11316 _codec ("JPEG still images");
11318 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
11321 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
11322 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
11323 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
11324 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
11325 _codec ("Motion-JPEG");
11327 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
11330 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
11331 _codec ("Motion-JPEG format B");
11332 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
11334 case GST_MAKE_FOURCC ('m', 'j', 'p', '2'):
11335 _codec ("JPEG-2000");
11336 /* override to what it should be according to spec, avoid palette_data */
11337 stream->bits_per_sample = 24;
11338 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
11340 case GST_MAKE_FOURCC ('S', 'V', 'Q', '3'):
11341 _codec ("Sorensen video v.3");
11342 caps = gst_caps_new_simple ("video/x-svq",
11343 "svqversion", G_TYPE_INT, 3, NULL);
11345 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
11346 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
11347 _codec ("Sorensen video v.1");
11348 caps = gst_caps_new_simple ("video/x-svq",
11349 "svqversion", G_TYPE_INT, 1, NULL);
11351 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
11352 caps = gst_caps_new_empty_simple ("video/x-raw");
11353 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
11354 _codec ("Windows Raw RGB");
11356 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
11360 bps = QT_UINT16 (stsd_data + 98);
11363 format = GST_VIDEO_FORMAT_RGB15;
11366 format = GST_VIDEO_FORMAT_RGB16;
11369 format = GST_VIDEO_FORMAT_RGB;
11372 format = GST_VIDEO_FORMAT_ARGB;
11380 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
11381 format = GST_VIDEO_FORMAT_I420;
11383 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
11384 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
11385 format = GST_VIDEO_FORMAT_I420;
11387 case GST_MAKE_FOURCC ('2', 'v', 'u', 'y'):
11388 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
11389 format = GST_VIDEO_FORMAT_UYVY;
11391 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
11392 format = GST_VIDEO_FORMAT_v308;
11394 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
11395 format = GST_VIDEO_FORMAT_v216;
11397 case GST_MAKE_FOURCC ('v', '2', '1', '0'):
11398 format = GST_VIDEO_FORMAT_v210;
11400 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
11401 format = GST_VIDEO_FORMAT_r210;
11403 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
11404 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
11405 format = GST_VIDEO_FORMAT_v410;
11408 /* Packed YUV 4:4:4:4 8 bit in 32 bits
11409 * but different order than AYUV
11410 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
11411 format = GST_VIDEO_FORMAT_v408;
11414 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
11415 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
11416 _codec ("MPEG-1 video");
11417 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
11418 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11420 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
11421 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
11422 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
11423 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
11424 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
11425 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
11426 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
11427 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
11428 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
11429 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
11430 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
11431 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
11432 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
11433 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
11434 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
11435 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
11436 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
11437 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
11438 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
11439 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
11440 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
11441 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
11442 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
11443 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
11444 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
11445 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
11446 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
11447 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
11448 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
11449 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
11450 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
11451 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
11452 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
11453 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
11454 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
11455 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
11456 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
11457 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
11458 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
11459 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
11460 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
11461 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
11462 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
11463 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
11464 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
11465 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
11466 _codec ("MPEG-2 video");
11467 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
11468 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11470 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
11471 _codec ("GIF still images");
11472 caps = gst_caps_new_empty_simple ("image/gif");
11474 case GST_MAKE_FOURCC ('h', '2', '6', '3'):
11475 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
11476 case GST_MAKE_FOURCC ('s', '2', '6', '3'):
11477 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
11479 /* ffmpeg uses the height/width props, don't know why */
11480 caps = gst_caps_new_simple ("video/x-h263",
11481 "variant", G_TYPE_STRING, "itu", NULL);
11483 case GST_MAKE_FOURCC ('m', 'p', '4', 'v'):
11484 case GST_MAKE_FOURCC ('M', 'P', '4', 'V'):
11485 _codec ("MPEG-4 video");
11486 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
11487 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11489 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
11490 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
11491 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
11492 caps = gst_caps_new_simple ("video/x-msmpeg",
11493 "msmpegversion", G_TYPE_INT, 43, NULL);
11495 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
11497 caps = gst_caps_new_simple ("video/x-divx",
11498 "divxversion", G_TYPE_INT, 3, NULL);
11500 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
11501 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
11503 caps = gst_caps_new_simple ("video/x-divx",
11504 "divxversion", G_TYPE_INT, 4, NULL);
11506 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
11508 caps = gst_caps_new_simple ("video/x-divx",
11509 "divxversion", G_TYPE_INT, 5, NULL);
11512 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
11513 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
11514 case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
11515 case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
11516 case GST_MAKE_FOURCC ('F', 'M', 'P', '4'):
11517 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
11518 caps = gst_caps_new_simple ("video/mpeg",
11519 "mpegversion", G_TYPE_INT, 4, NULL);
11521 *codec_name = g_strdup ("MPEG-4");
11524 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
11525 _codec ("Cinepak");
11526 caps = gst_caps_new_empty_simple ("video/x-cinepak");
11528 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
11529 _codec ("Apple QuickDraw");
11530 caps = gst_caps_new_empty_simple ("video/x-qdrw");
11532 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
11533 _codec ("Apple video");
11534 caps = gst_caps_new_empty_simple ("video/x-apple-video");
11536 case GST_MAKE_FOURCC ('H', '2', '6', '4'):
11537 case GST_MAKE_FOURCC ('a', 'v', 'c', '1'):
11538 _codec ("H.264 / AVC");
11539 caps = gst_caps_new_simple ("video/x-h264",
11540 "stream-format", G_TYPE_STRING, "avc",
11541 "alignment", G_TYPE_STRING, "au", NULL);
11543 case GST_MAKE_FOURCC ('a', 'v', 'c', '3'):
11544 _codec ("H.264 / AVC");
11545 caps = gst_caps_new_simple ("video/x-h264",
11546 "stream-format", G_TYPE_STRING, "avc3",
11547 "alignment", G_TYPE_STRING, "au", NULL);
11549 case GST_MAKE_FOURCC ('H', '2', '6', '5'):
11550 case GST_MAKE_FOURCC ('h', 'v', 'c', '1'):
11551 _codec ("H.265 / HEVC");
11552 caps = gst_caps_new_simple ("video/x-h265",
11553 "stream-format", G_TYPE_STRING, "hvc1",
11554 "alignment", G_TYPE_STRING, "au", NULL);
11556 case GST_MAKE_FOURCC ('h', 'e', 'v', '1'):
11557 _codec ("H.265 / HEVC");
11558 caps = gst_caps_new_simple ("video/x-h265",
11559 "stream-format", G_TYPE_STRING, "hev1",
11560 "alignment", G_TYPE_STRING, "au", NULL);
11562 case GST_MAKE_FOURCC ('r', 'l', 'e', ' '):
11563 _codec ("Run-length encoding");
11564 caps = gst_caps_new_simple ("video/x-rle",
11565 "layout", G_TYPE_STRING, "quicktime", NULL);
11567 case GST_MAKE_FOURCC ('W', 'R', 'L', 'E'):
11568 _codec ("Run-length encoding");
11569 caps = gst_caps_new_simple ("video/x-rle",
11570 "layout", G_TYPE_STRING, "microsoft", NULL);
11572 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
11573 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
11574 _codec ("Indeo Video 3");
11575 caps = gst_caps_new_simple ("video/x-indeo",
11576 "indeoversion", G_TYPE_INT, 3, NULL);
11578 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
11579 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
11580 _codec ("Intel Video 4");
11581 caps = gst_caps_new_simple ("video/x-indeo",
11582 "indeoversion", G_TYPE_INT, 4, NULL);
11584 case GST_MAKE_FOURCC ('d', 'v', 'c', 'p'):
11585 case GST_MAKE_FOURCC ('d', 'v', 'c', ' '):
11586 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
11587 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
11588 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
11589 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
11590 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
11591 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
11592 _codec ("DV Video");
11593 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
11594 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11596 case GST_MAKE_FOURCC ('d', 'v', '5', 'n'): /* DVCPRO50 NTSC */
11597 case GST_MAKE_FOURCC ('d', 'v', '5', 'p'): /* DVCPRO50 PAL */
11598 _codec ("DVCPro50 Video");
11599 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
11600 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11602 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
11603 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
11604 _codec ("DVCProHD Video");
11605 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
11606 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11608 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
11609 _codec ("Apple Graphics (SMC)");
11610 caps = gst_caps_new_empty_simple ("video/x-smc");
11612 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
11614 caps = gst_caps_new_empty_simple ("video/x-vp3");
11616 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
11617 _codec ("VP6 Flash");
11618 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
11620 case GST_MAKE_FOURCC ('X', 'i', 'T', 'h'):
11622 caps = gst_caps_new_empty_simple ("video/x-theora");
11623 /* theora uses one byte of padding in the data stream because it does not
11624 * allow 0 sized packets while theora does */
11625 stream->padding = 1;
11627 case GST_MAKE_FOURCC ('d', 'r', 'a', 'c'):
11629 caps = gst_caps_new_empty_simple ("video/x-dirac");
11631 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
11632 _codec ("TIFF still images");
11633 caps = gst_caps_new_empty_simple ("image/tiff");
11635 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
11636 _codec ("Apple Intermediate Codec");
11637 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
11639 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
11640 _codec ("AVID DNxHD");
11641 caps = gst_caps_from_string ("video/x-dnxhd");
11643 case GST_MAKE_FOURCC ('V', 'P', '8', '0'):
11644 _codec ("On2 VP8");
11645 caps = gst_caps_from_string ("video/x-vp8");
11647 case GST_MAKE_FOURCC ('a', 'p', 'c', 's'):
11648 _codec ("Apple ProRes LT");
11650 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
11653 case GST_MAKE_FOURCC ('a', 'p', 'c', 'h'):
11654 _codec ("Apple ProRes HQ");
11656 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
11659 case GST_MAKE_FOURCC ('a', 'p', 'c', 'n'):
11660 _codec ("Apple ProRes");
11662 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
11665 case GST_MAKE_FOURCC ('a', 'p', 'c', 'o'):
11666 _codec ("Apple ProRes Proxy");
11668 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
11671 case GST_MAKE_FOURCC ('a', 'p', '4', 'h'):
11672 _codec ("Apple ProRes 4444");
11674 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
11677 case GST_MAKE_FOURCC ('v', 'c', '-', '1'):
11680 caps = gst_caps_new_simple ("video/x-wmv",
11681 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
11683 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
11686 char *s, fourstr[5];
11688 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11689 s = g_strdup_printf ("video/x-gst-fourcc-%s", g_strstrip (fourstr));
11690 caps = gst_caps_new_empty_simple (s);
11695 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
11698 gst_video_info_init (&info);
11699 gst_video_info_set_format (&info, format, stream->width, stream->height);
11701 caps = gst_video_info_to_caps (&info);
11702 *codec_name = gst_pb_utils_get_codec_description (caps);
11704 /* enable clipping for raw video streams */
11705 stream->need_clip = TRUE;
11712 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
11713 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
11716 const GstStructure *s;
11720 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
11723 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
11724 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
11725 _codec ("Raw 8-bit PCM audio");
11726 caps = gst_caps_new_simple ("audio/x-raw",
11727 "format", G_TYPE_STRING, "U8",
11728 "layout", G_TYPE_STRING, "interleaved", NULL);
11730 case GST_MAKE_FOURCC ('t', 'w', 'o', 's'):
11731 endian = G_BIG_ENDIAN;
11733 case GST_MAKE_FOURCC ('s', 'o', 'w', 't'):
11737 GstAudioFormat format;
11740 endian = G_LITTLE_ENDIAN;
11742 depth = stream->bytes_per_packet * 8;
11743 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
11745 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
11749 caps = gst_caps_new_simple ("audio/x-raw",
11750 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
11751 "layout", G_TYPE_STRING, "interleaved", NULL);
11754 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
11755 _codec ("Raw 64-bit floating-point audio");
11756 caps = gst_caps_new_simple ("audio/x-raw",
11757 "format", G_TYPE_STRING, "F64BE",
11758 "layout", G_TYPE_STRING, "interleaved", NULL);
11760 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
11761 _codec ("Raw 32-bit floating-point audio");
11762 caps = gst_caps_new_simple ("audio/x-raw",
11763 "format", G_TYPE_STRING, "F32BE",
11764 "layout", G_TYPE_STRING, "interleaved", NULL);
11767 _codec ("Raw 24-bit PCM audio");
11768 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
11770 caps = gst_caps_new_simple ("audio/x-raw",
11771 "format", G_TYPE_STRING, "S24BE",
11772 "layout", G_TYPE_STRING, "interleaved", NULL);
11774 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
11775 _codec ("Raw 32-bit PCM audio");
11776 caps = gst_caps_new_simple ("audio/x-raw",
11777 "format", G_TYPE_STRING, "S32BE",
11778 "layout", G_TYPE_STRING, "interleaved", NULL);
11780 case GST_MAKE_FOURCC ('u', 'l', 'a', 'w'):
11781 _codec ("Mu-law audio");
11782 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
11784 case GST_MAKE_FOURCC ('a', 'l', 'a', 'w'):
11785 _codec ("A-law audio");
11786 caps = gst_caps_new_empty_simple ("audio/x-alaw");
11790 _codec ("Microsoft ADPCM");
11791 /* Microsoft ADPCM-ACM code 2 */
11792 caps = gst_caps_new_simple ("audio/x-adpcm",
11793 "layout", G_TYPE_STRING, "microsoft", NULL);
11797 _codec ("DVI/IMA ADPCM");
11798 caps = gst_caps_new_simple ("audio/x-adpcm",
11799 "layout", G_TYPE_STRING, "dvi", NULL);
11803 _codec ("DVI/Intel IMA ADPCM");
11804 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
11805 caps = gst_caps_new_simple ("audio/x-adpcm",
11806 "layout", G_TYPE_STRING, "quicktime", NULL);
11810 /* MPEG layer 3, CBR only (pre QT4.1) */
11811 case GST_MAKE_FOURCC ('.', 'm', 'p', '3'):
11812 _codec ("MPEG-1 layer 3");
11813 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
11814 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
11815 "mpegversion", G_TYPE_INT, 1, NULL);
11818 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
11819 _codec ("EAC-3 audio");
11820 caps = gst_caps_new_simple ("audio/x-eac3",
11821 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
11822 stream->sampled = TRUE;
11824 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
11825 case GST_MAKE_FOURCC ('a', 'c', '-', '3'):
11826 _codec ("AC-3 audio");
11827 caps = gst_caps_new_simple ("audio/x-ac3",
11828 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
11829 stream->sampled = TRUE;
11831 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
11832 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
11833 _codec ("DTS audio");
11834 caps = gst_caps_new_simple ("audio/x-dts",
11835 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
11836 stream->sampled = TRUE;
11838 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
11839 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
11840 _codec ("DTS-HD audio");
11841 caps = gst_caps_new_simple ("audio/x-dts",
11842 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
11843 stream->sampled = TRUE;
11845 case GST_MAKE_FOURCC ('M', 'A', 'C', '3'):
11847 caps = gst_caps_new_simple ("audio/x-mace",
11848 "maceversion", G_TYPE_INT, 3, NULL);
11850 case GST_MAKE_FOURCC ('M', 'A', 'C', '6'):
11852 caps = gst_caps_new_simple ("audio/x-mace",
11853 "maceversion", G_TYPE_INT, 6, NULL);
11855 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
11857 caps = gst_caps_new_empty_simple ("application/ogg");
11859 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
11860 _codec ("DV audio");
11861 caps = gst_caps_new_empty_simple ("audio/x-dv");
11863 case GST_MAKE_FOURCC ('m', 'p', '4', 'a'):
11864 _codec ("MPEG-4 AAC audio");
11865 caps = gst_caps_new_simple ("audio/mpeg",
11866 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
11867 "stream-format", G_TYPE_STRING, "raw", NULL);
11869 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
11870 _codec ("QDesign Music");
11871 caps = gst_caps_new_empty_simple ("audio/x-qdm");
11873 case GST_MAKE_FOURCC ('Q', 'D', 'M', '2'):
11874 _codec ("QDesign Music v.2");
11875 /* FIXME: QDesign music version 2 (no constant) */
11876 if (FALSE && data) {
11877 caps = gst_caps_new_simple ("audio/x-qdm2",
11878 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
11879 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
11880 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
11882 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
11885 case GST_MAKE_FOURCC ('a', 'g', 's', 'm'):
11886 _codec ("GSM audio");
11887 caps = gst_caps_new_empty_simple ("audio/x-gsm");
11889 case GST_MAKE_FOURCC ('s', 'a', 'm', 'r'):
11890 _codec ("AMR audio");
11891 caps = gst_caps_new_empty_simple ("audio/AMR");
11893 case GST_MAKE_FOURCC ('s', 'a', 'w', 'b'):
11894 _codec ("AMR-WB audio");
11895 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
11897 case GST_MAKE_FOURCC ('i', 'm', 'a', '4'):
11898 _codec ("Quicktime IMA ADPCM");
11899 caps = gst_caps_new_simple ("audio/x-adpcm",
11900 "layout", G_TYPE_STRING, "quicktime", NULL);
11902 case GST_MAKE_FOURCC ('a', 'l', 'a', 'c'):
11903 _codec ("Apple lossless audio");
11904 caps = gst_caps_new_empty_simple ("audio/x-alac");
11906 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
11907 _codec ("QualComm PureVoice");
11908 caps = gst_caps_from_string ("audio/qcelp");
11910 case GST_MAKE_FOURCC ('w', 'm', 'a', ' '):
11913 caps = gst_caps_new_empty_simple ("audio/x-wma");
11915 case GST_MAKE_FOURCC ('l', 'p', 'c', 'm'):
11920 GstAudioFormat format;
11923 FLAG_IS_FLOAT = 0x1,
11924 FLAG_IS_BIG_ENDIAN = 0x2,
11925 FLAG_IS_SIGNED = 0x4,
11926 FLAG_IS_PACKED = 0x8,
11927 FLAG_IS_ALIGNED_HIGH = 0x10,
11928 FLAG_IS_NON_INTERLEAVED = 0x20
11930 _codec ("Raw LPCM audio");
11932 if (data && len >= 56) {
11933 depth = QT_UINT32 (data + 40);
11934 flags = QT_UINT32 (data + 44);
11935 width = QT_UINT32 (data + 48) * 8 / stream->n_channels;
11937 if ((flags & FLAG_IS_FLOAT) == 0) {
11942 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
11943 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
11944 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
11945 caps = gst_caps_new_simple ("audio/x-raw",
11946 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
11947 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
11948 "non-interleaved" : "interleaved", NULL);
11953 if (flags & FLAG_IS_BIG_ENDIAN)
11954 format = GST_AUDIO_FORMAT_F64BE;
11956 format = GST_AUDIO_FORMAT_F64LE;
11958 if (flags & FLAG_IS_BIG_ENDIAN)
11959 format = GST_AUDIO_FORMAT_F32BE;
11961 format = GST_AUDIO_FORMAT_F32LE;
11963 caps = gst_caps_new_simple ("audio/x-raw",
11964 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
11965 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
11966 "non-interleaved" : "interleaved", NULL);
11970 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
11974 char *s, fourstr[5];
11976 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11977 s = g_strdup_printf ("audio/x-gst-fourcc-%s", g_strstrip (fourstr));
11978 caps = gst_caps_new_empty_simple (s);
11984 GstCaps *templ_caps =
11985 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
11986 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
11987 gst_caps_unref (caps);
11988 gst_caps_unref (templ_caps);
11989 caps = intersection;
11992 /* enable clipping for raw audio streams */
11993 s = gst_caps_get_structure (caps, 0);
11994 name = gst_structure_get_name (s);
11995 if (g_str_has_prefix (name, "audio/x-raw")) {
11996 stream->need_clip = TRUE;
11997 stream->max_buffer_size = 4096 * stream->bytes_per_frame;
11998 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
12004 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
12005 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
12009 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
12012 case GST_MAKE_FOURCC ('m', 'p', '4', 's'):
12013 _codec ("DVD subtitle");
12014 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
12015 stream->need_process = TRUE;
12017 case GST_MAKE_FOURCC ('t', 'e', 'x', 't'):
12018 _codec ("Quicktime timed text");
12020 case GST_MAKE_FOURCC ('t', 'x', '3', 'g'):
12021 _codec ("3GPP timed text");
12023 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
12025 /* actual text piece needs to be extracted */
12026 stream->need_process = TRUE;
12030 char *s, fourstr[5];
12032 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12033 s = g_strdup_printf ("text/x-gst-fourcc-%s", g_strstrip (fourstr));
12034 caps = gst_caps_new_empty_simple (s);
12042 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
12043 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
12048 case GST_MAKE_FOURCC ('m', '1', 'v', ' '):
12049 _codec ("MPEG 1 video");
12050 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
12051 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);