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 qtdemux->offset += length; /* skip moof and keep going */
3319 if (qtdemux->got_moov) {
3320 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
3331 GST_LOG_OBJECT (qtdemux,
3332 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
3333 GST_FOURCC_ARGS (fourcc), cur_offset);
3334 qtdemux->offset = add_offset (qtdemux->offset, length);
3339 GstBuffer *moov = NULL;
3341 if (qtdemux->got_moov) {
3342 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
3343 qtdemux->offset = add_offset (qtdemux->offset, length);
3347 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
3348 if (ret != GST_FLOW_OK)
3350 gst_buffer_map (moov, &map, GST_MAP_READ);
3352 if (length != map.size) {
3353 /* Some files have a 'moov' atom at the end of the file which contains
3354 * a terminal 'free' atom where the body of the atom is missing.
3355 * Check for, and permit, this special case.
3357 if (map.size >= 8) {
3358 guint8 *final_data = map.data + (map.size - 8);
3359 guint32 final_length = QT_UINT32 (final_data);
3360 guint32 final_fourcc = QT_FOURCC (final_data + 4);
3362 if (final_fourcc == FOURCC_free
3363 && map.size + final_length - 8 == length) {
3364 /* Ok, we've found that special case. Allocate a new buffer with
3365 * that free atom actually present. */
3366 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
3367 gst_buffer_fill (newmoov, 0, map.data, map.size);
3368 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
3369 gst_buffer_unmap (moov, &map);
3370 gst_buffer_unref (moov);
3372 gst_buffer_map (moov, &map, GST_MAP_READ);
3377 if (length != map.size) {
3378 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
3379 (_("This file is incomplete and cannot be played.")),
3380 ("We got less than expected (received %" G_GSIZE_FORMAT
3381 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
3382 (guint) length, cur_offset));
3383 gst_buffer_unmap (moov, &map);
3384 gst_buffer_unref (moov);
3385 ret = GST_FLOW_ERROR;
3388 qtdemux->offset += length;
3390 qtdemux_parse_moov (qtdemux, map.data, length);
3391 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
3393 qtdemux_parse_tree (qtdemux);
3394 g_node_destroy (qtdemux->moov_node);
3395 gst_buffer_unmap (moov, &map);
3396 gst_buffer_unref (moov);
3397 qtdemux->moov_node = NULL;
3398 qtdemux->got_moov = TRUE;
3404 GstBuffer *ftyp = NULL;
3406 /* extract major brand; might come in handy for ISO vs QT issues */
3407 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
3408 if (ret != GST_FLOW_OK)
3410 qtdemux->offset += length;
3411 gst_buffer_map (ftyp, &map, GST_MAP_READ);
3412 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
3413 gst_buffer_unmap (ftyp, &map);
3414 gst_buffer_unref (ftyp);
3419 GstBuffer *uuid = NULL;
3421 /* uuid are extension atoms */
3422 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
3423 if (ret != GST_FLOW_OK)
3425 qtdemux->offset += length;
3426 gst_buffer_map (uuid, &map, GST_MAP_READ);
3427 qtdemux_parse_uuid (qtdemux, map.data, map.size);
3428 gst_buffer_unmap (uuid, &map);
3429 gst_buffer_unref (uuid);
3434 GstBuffer *sidx = NULL;
3435 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
3436 if (ret != GST_FLOW_OK)
3438 qtdemux->offset += length;
3439 gst_buffer_map (sidx, &map, GST_MAP_READ);
3440 qtdemux_parse_sidx (qtdemux, map.data, map.size);
3441 gst_buffer_unmap (sidx, &map);
3442 gst_buffer_unref (sidx);
3447 GstBuffer *unknown = NULL;
3449 GST_LOG_OBJECT (qtdemux,
3450 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
3451 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
3453 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
3454 if (ret != GST_FLOW_OK)
3456 gst_buffer_map (unknown, &map, GST_MAP_READ);
3457 GST_MEMDUMP ("Unknown tag", map.data, map.size);
3458 gst_buffer_unmap (unknown, &map);
3459 gst_buffer_unref (unknown);
3460 qtdemux->offset += length;
3466 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
3467 /* digested all data, show what we have */
3468 qtdemux_prepare_streams (qtdemux);
3469 ret = qtdemux_expose_streams (qtdemux);
3471 qtdemux->state = QTDEMUX_STATE_MOVIE;
3472 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
3479 /* Seeks to the previous keyframe of the indexed stream and
3480 * aligns other streams with respect to the keyframe timestamp
3481 * of indexed stream. Only called in case of Reverse Playback
3483 static GstFlowReturn
3484 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
3487 guint32 seg_idx = 0, k_index = 0;
3488 guint32 ref_seg_idx, ref_k_index;
3489 GstClockTime k_pos = 0, last_stop = 0;
3490 QtDemuxSegment *seg = NULL;
3491 QtDemuxStream *ref_str = NULL;
3492 guint64 seg_media_start_mov; /* segment media start time in mov format */
3495 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
3496 * and finally align all the other streams on that timestamp with their
3497 * respective keyframes */
3498 for (n = 0; n < qtdemux->n_streams; n++) {
3499 QtDemuxStream *str = qtdemux->streams[n];
3501 /* No candidate yet, take the first stream */
3507 /* So that stream has a segment, we prefer video streams */
3508 if (str->subtype == FOURCC_vide) {
3514 if (G_UNLIKELY (!ref_str)) {
3515 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
3519 if (G_UNLIKELY (!ref_str->from_sample)) {
3520 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
3524 /* So that stream has been playing from from_sample to to_sample. We will
3525 * get the timestamp of the previous sample and search for a keyframe before
3526 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
3527 if (ref_str->subtype == FOURCC_vide) {
3528 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
3529 ref_str->from_sample - 1);
3531 if (ref_str->from_sample >= 10)
3532 k_index = ref_str->from_sample - 10;
3538 ref_str->samples[k_index].timestamp +
3539 ref_str->samples[k_index].pts_offset;
3541 /* get current segment for that stream */
3542 seg = &ref_str->segments[ref_str->segment_index];
3543 /* Use segment start in original timescale for comparisons */
3544 seg_media_start_mov = seg->trak_media_start;
3546 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
3547 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT "\n",
3548 k_index, target_ts, seg_media_start_mov,
3549 GST_TIME_ARGS (seg->media_start));
3551 /* Crawl back through segments to find the one containing this I frame */
3552 while (target_ts < seg_media_start_mov) {
3553 GST_DEBUG_OBJECT (qtdemux,
3554 "keyframe position (sample %u) is out of segment %u " " target %"
3555 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
3556 ref_str->segment_index, target_ts, seg_media_start_mov);
3558 if (G_UNLIKELY (!ref_str->segment_index)) {
3559 /* Reached first segment, let's consider it's EOS */
3562 ref_str->segment_index--;
3563 seg = &ref_str->segments[ref_str->segment_index];
3564 /* Use segment start in original timescale for comparisons */
3565 seg_media_start_mov = seg->trak_media_start;
3567 /* Calculate time position of the keyframe and where we should stop */
3569 QTSTREAMTIME_TO_GSTTIME (ref_str,
3570 target_ts - seg->trak_media_start) + seg->time;
3572 QTSTREAMTIME_TO_GSTTIME (ref_str,
3573 ref_str->samples[ref_str->from_sample].timestamp -
3574 seg->trak_media_start) + seg->time;
3576 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
3577 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
3578 k_index, GST_TIME_ARGS (k_pos));
3580 /* Set last_stop with the keyframe timestamp we pushed of that stream */
3581 qtdemux->segment.position = last_stop;
3582 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
3583 GST_TIME_ARGS (last_stop));
3585 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
3586 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
3590 ref_seg_idx = ref_str->segment_index;
3591 ref_k_index = k_index;
3593 /* Align them all on this */
3594 for (n = 0; n < qtdemux->n_streams; n++) {
3596 GstClockTime seg_time = 0;
3597 QtDemuxStream *str = qtdemux->streams[n];
3599 /* aligning reference stream again might lead to backing up to yet another
3600 * keyframe (due to timestamp rounding issues),
3601 * potentially putting more load on downstream; so let's try to avoid */
3602 if (str == ref_str) {
3603 seg_idx = ref_seg_idx;
3604 seg = &str->segments[seg_idx];
3605 k_index = ref_k_index;
3606 GST_DEBUG_OBJECT (qtdemux, "reference stream %d segment %d, "
3607 "sample at index %d", n, ref_str->segment_index, k_index);
3609 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
3610 GST_DEBUG_OBJECT (qtdemux,
3611 "stream %d align segment %d for keyframe pos %" GST_TIME_FORMAT, n,
3612 seg_idx, GST_TIME_ARGS (k_pos));
3614 /* get segment and time in the segment */
3615 seg = &str->segments[seg_idx];
3616 seg_time = k_pos - seg->time;
3618 /* get the media time in the segment.
3619 * No adjustment for empty "filler" segments */
3620 if (seg->media_start != GST_CLOCK_TIME_NONE)
3621 seg_time += seg->media_start;
3623 /* get the index of the sample with media time */
3624 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
3625 GST_DEBUG_OBJECT (qtdemux,
3626 "stream %d sample for %" GST_TIME_FORMAT " at %u", n,
3627 GST_TIME_ARGS (seg_time), index);
3629 /* find previous keyframe */
3630 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index);
3633 /* Remember until where we want to go */
3634 str->to_sample = str->from_sample - 1;
3635 /* Define our time position */
3637 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
3638 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
3639 if (seg->media_start != GST_CLOCK_TIME_NONE)
3640 str->time_position -= seg->media_start;
3642 /* Now seek back in time */
3643 gst_qtdemux_move_stream (qtdemux, str, k_index);
3644 GST_DEBUG_OBJECT (qtdemux, "stream %d keyframe at %u, time position %"
3645 GST_TIME_FORMAT " playing from sample %u to %u", n, k_index,
3646 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
3652 return GST_FLOW_EOS;
3655 /* activate the given segment number @seg_idx of @stream at time @offset.
3656 * @offset is an absolute global position over all the segments.
3658 * This will push out a NEWSEGMENT event with the right values and
3659 * position the stream index to the first decodable sample before
3665 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
3666 guint32 seg_idx, GstClockTime offset)
3669 QtDemuxSegment *segment;
3670 guint32 index, kf_index;
3671 GstClockTime seg_time;
3672 GstClockTime start, stop, time;
3675 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
3676 seg_idx, GST_TIME_ARGS (offset));
3678 /* update the current segment */
3679 stream->segment_index = seg_idx;
3681 /* get the segment */
3682 segment = &stream->segments[seg_idx];
3684 if (G_UNLIKELY (offset < segment->time)) {
3685 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
3686 GST_TIME_ARGS (segment->time));
3690 /* segment lies beyond total indicated duration */
3691 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
3692 segment->time > qtdemux->segment.duration)) {
3693 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
3694 " < segment->time %" GST_TIME_FORMAT,
3695 GST_TIME_ARGS (qtdemux->segment.duration),
3696 GST_TIME_ARGS (segment->time));
3700 /* get time in this segment */
3701 seg_time = offset - segment->time;
3703 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
3704 GST_TIME_ARGS (seg_time));
3706 if (G_UNLIKELY (seg_time > segment->duration)) {
3707 GST_LOG_OBJECT (stream->pad,
3708 "seg_time > segment->duration %" GST_TIME_FORMAT,
3709 GST_TIME_ARGS (segment->duration));
3710 seg_time = segment->duration;
3713 /* qtdemux->segment.stop is in outside-time-realm, whereas
3714 * segment->media_stop is in track-time-realm.
3716 * In order to compare the two, we need to bring segment.stop
3717 * into the track-time-realm */
3719 stop = qtdemux->segment.stop;
3720 if (stop == GST_CLOCK_TIME_NONE)
3721 stop = qtdemux->segment.duration;
3722 if (stop == GST_CLOCK_TIME_NONE)
3723 stop = segment->media_stop;
3726 MIN (segment->media_stop, stop - segment->time + segment->media_start);
3728 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
3729 start = segment->time + seg_time;
3731 stop = start - seg_time + segment->duration;
3732 } else if (qtdemux->segment.rate >= 0) {
3733 start = MIN (segment->media_start + seg_time, stop);
3736 if (segment->media_start >= qtdemux->segment.start) {
3737 time = segment->time;
3739 time = segment->time + (qtdemux->segment.start - segment->media_start);
3742 start = MAX (segment->media_start, qtdemux->segment.start);
3743 stop = MIN (segment->media_start + seg_time, stop);
3746 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
3747 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
3748 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
3750 /* combine global rate with that of the segment */
3751 rate = segment->rate * qtdemux->segment.rate;
3753 /* Copy flags from main segment */
3754 stream->segment.flags = qtdemux->segment.flags;
3756 /* accumulate previous segments */
3757 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
3758 stream->accumulated_base += (stream->segment.stop - stream->segment.start) /
3759 ABS (stream->segment.rate);
3761 /* update the segment values used for clipping */
3762 stream->segment.offset = qtdemux->segment.offset;
3763 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
3764 stream->segment.applied_rate = qtdemux->segment.applied_rate;
3765 stream->segment.rate = rate;
3766 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
3767 stream->cslg_shift);
3768 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
3769 stream->cslg_shift);
3770 stream->segment.time = time;
3771 stream->segment.position = stream->segment.start;
3773 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
3776 /* now prepare and send the segment */
3778 event = gst_event_new_segment (&stream->segment);
3779 if (stream->segment_seqnum) {
3780 gst_event_set_seqnum (event, stream->segment_seqnum);
3782 gst_pad_push_event (stream->pad, event);
3783 /* assume we can send more data now */
3784 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
3785 /* clear to send tags on this pad now */
3786 gst_qtdemux_push_tags (qtdemux, stream);
3789 /* in the fragmented case, we pick a fragment that starts before our
3790 * desired position and rely on downstream to wait for a keyframe
3791 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
3792 * tfra entries tells us which trun/sample the key unit is in, but we don't
3793 * make use of this additional information at the moment) */
3794 if (qtdemux->fragmented) {
3795 stream->to_sample = G_MAXUINT32;
3799 /* and move to the keyframe before the indicated media time of the
3801 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
3802 if (qtdemux->segment.rate >= 0) {
3803 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
3804 stream->to_sample = G_MAXUINT32;
3805 GST_DEBUG_OBJECT (stream->pad,
3806 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
3807 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
3808 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
3810 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
3811 stream->to_sample = index;
3812 GST_DEBUG_OBJECT (stream->pad,
3813 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
3814 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
3815 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
3818 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
3819 "this is an empty segment");
3823 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
3824 * encountered an error and printed a message so we return appropriately */
3828 /* we're at the right spot */
3829 if (index == stream->sample_index) {
3830 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
3834 /* find keyframe of the target index */
3835 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index);
3838 /* indent does stupid stuff with stream->samples[].timestamp */
3840 /* if we move forwards, we don't have to go back to the previous
3841 * keyframe since we already sent that. We can also just jump to
3842 * the keyframe right before the target index if there is one. */
3843 if (index > stream->sample_index) {
3844 /* moving forwards check if we move past a keyframe */
3845 if (kf_index > stream->sample_index) {
3846 GST_DEBUG_OBJECT (stream->pad,
3847 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
3848 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
3849 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
3850 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
3852 GST_DEBUG_OBJECT (stream->pad,
3853 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
3854 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
3855 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
3858 GST_DEBUG_OBJECT (stream->pad,
3859 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
3860 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
3861 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
3862 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
3870 /* prepare to get the current sample of @stream, getting essential values.
3872 * This function will also prepare and send the segment when needed.
3874 * Return FALSE if the stream is EOS.
3879 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
3880 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
3881 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
3882 gboolean * keyframe)
3884 QtDemuxSample *sample;
3885 GstClockTime time_position;
3888 g_return_val_if_fail (stream != NULL, FALSE);
3890 time_position = stream->time_position;
3891 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
3894 seg_idx = stream->segment_index;
3895 if (G_UNLIKELY (seg_idx == -1)) {
3896 /* find segment corresponding to time_position if we are looking
3898 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
3901 /* different segment, activate it, sample_index will be set. */
3902 if (G_UNLIKELY (stream->segment_index != seg_idx))
3903 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
3905 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->segments[stream->
3907 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
3909 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
3910 " prepare empty sample");
3913 *pts = *dts = time_position;
3914 *duration = seg->duration - (time_position - seg->time);
3921 if (stream->sample_index == -1)
3922 stream->sample_index = 0;
3924 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
3925 stream->sample_index, stream->n_samples);
3927 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
3928 if (!qtdemux->fragmented)
3931 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
3935 GST_OBJECT_LOCK (qtdemux);
3936 flow = qtdemux_add_fragmented_samples (qtdemux);
3937 GST_OBJECT_UNLOCK (qtdemux);
3939 if (flow != GST_FLOW_OK)
3942 while (stream->sample_index >= stream->n_samples);
3945 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
3946 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
3947 stream->sample_index);
3951 /* now get the info for the sample we're at */
3952 sample = &stream->samples[stream->sample_index];
3954 *dts = QTSAMPLE_DTS (stream, sample);
3955 *pts = QTSAMPLE_PTS (stream, sample);
3956 *offset = sample->offset;
3957 *size = sample->size;
3958 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
3959 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
3966 stream->time_position = GST_CLOCK_TIME_NONE;
3971 /* move to the next sample in @stream.
3973 * Moves to the next segment when needed.
3976 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
3978 QtDemuxSample *sample;
3979 QtDemuxSegment *segment;
3981 /* get current segment */
3982 segment = &stream->segments[stream->segment_index];
3984 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
3985 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
3989 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
3990 /* Mark the stream as EOS */
3991 GST_DEBUG_OBJECT (qtdemux,
3992 "reached max allowed sample %u, mark EOS", stream->to_sample);
3993 stream->time_position = GST_CLOCK_TIME_NONE;
3997 /* move to next sample */
3998 stream->sample_index++;
3999 stream->offset_in_sample = 0;
4001 /* reached the last sample, we need the next segment */
4002 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
4005 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4006 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4007 stream->sample_index);
4011 /* get next sample */
4012 sample = &stream->samples[stream->sample_index];
4014 /* see if we are past the segment */
4015 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
4018 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
4019 /* inside the segment, update time_position, looks very familiar to
4020 * GStreamer segments, doesn't it? */
4021 stream->time_position =
4022 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
4024 /* not yet in segment, time does not yet increment. This means
4025 * that we are still prerolling keyframes to the decoder so it can
4026 * decode the first sample of the segment. */
4027 stream->time_position = segment->time;
4031 /* move to the next segment */
4034 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
4036 if (stream->segment_index == stream->n_segments - 1) {
4037 /* are we at the end of the last segment, we're EOS */
4038 stream->time_position = GST_CLOCK_TIME_NONE;
4040 /* else we're only at the end of the current segment */
4041 stream->time_position = segment->stop_time;
4043 /* make sure we select a new segment */
4044 stream->segment_index = -1;
4049 gst_qtdemux_sync_streams (GstQTDemux * demux)
4053 if (demux->n_streams <= 1)
4056 for (i = 0; i < demux->n_streams; i++) {
4057 QtDemuxStream *stream;
4058 GstClockTime end_time;
4060 stream = demux->streams[i];
4065 /* TODO advance time on subtitle streams here, if any some day */
4067 /* some clips/trailers may have unbalanced streams at the end,
4068 * so send EOS on shorter stream to prevent stalling others */
4070 /* do not mess with EOS if SEGMENT seeking */
4071 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
4074 if (demux->pullbased) {
4075 /* loop mode is sample time based */
4076 if (!STREAM_IS_EOS (stream))
4079 /* push mode is byte position based */
4080 if (stream->n_samples &&
4081 stream->samples[stream->n_samples - 1].offset >= demux->offset)
4085 if (stream->sent_eos)
4088 /* only act if some gap */
4089 end_time = stream->segments[stream->n_segments - 1].stop_time;
4090 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
4091 ", stream end: %" GST_TIME_FORMAT,
4092 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
4093 if (GST_CLOCK_TIME_IS_VALID (end_time)
4094 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
4095 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
4096 GST_PAD_NAME (stream->pad));
4097 stream->sent_eos = TRUE;
4098 gst_pad_push_event (stream->pad, gst_event_new_eos ());
4103 /* EOS and NOT_LINKED need to be combined. This means that we return:
4105 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
4106 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
4108 static GstFlowReturn
4109 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
4112 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
4115 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
4118 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
4120 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
4124 /* the input buffer metadata must be writable. Returns NULL when the buffer is
4125 * completely clipped
4127 * Should be used only with raw buffers */
4129 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
4132 guint64 start, stop, cstart, cstop, diff;
4133 GstClockTime pts, duration;
4135 gint num_rate, denom_rate;
4140 osize = size = gst_buffer_get_size (buf);
4143 /* depending on the type, setup the clip parameters */
4144 if (stream->subtype == FOURCC_soun) {
4145 frame_size = stream->bytes_per_frame;
4146 num_rate = GST_SECOND;
4147 denom_rate = (gint) stream->rate;
4149 } else if (stream->subtype == FOURCC_vide) {
4151 num_rate = stream->fps_n;
4152 denom_rate = stream->fps_d;
4157 if (frame_size <= 0)
4158 goto bad_frame_size;
4160 /* we can only clip if we have a valid pts */
4161 pts = GST_BUFFER_PTS (buf);
4162 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
4165 duration = GST_BUFFER_DURATION (buf);
4167 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
4169 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
4173 stop = start + duration;
4175 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
4176 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
4179 /* see if some clipping happened */
4180 diff = cstart - start;
4186 /* bring clipped time to samples and to bytes */
4187 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
4190 GST_DEBUG_OBJECT (qtdemux,
4191 "clipping start to %" GST_TIME_FORMAT " %"
4192 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
4198 diff = stop - cstop;
4203 /* bring clipped time to samples and then to bytes */
4204 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
4206 GST_DEBUG_OBJECT (qtdemux,
4207 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
4208 " bytes", GST_TIME_ARGS (cstop), diff);
4213 if (offset != 0 || size != osize)
4214 gst_buffer_resize (buf, offset, size);
4216 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
4217 GST_BUFFER_PTS (buf) = pts;
4218 GST_BUFFER_DURATION (buf) = duration;
4222 /* dropped buffer */
4225 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
4230 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
4235 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
4240 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
4241 gst_buffer_unref (buf);
4246 /* the input buffer metadata must be writable,
4247 * but time/duration etc not yet set and need not be preserved */
4249 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
4256 /* not many cases for now */
4257 if (G_UNLIKELY (stream->fourcc == FOURCC_mp4s)) {
4258 /* send a one time dvd clut event */
4259 if (stream->pending_event && stream->pad)
4260 gst_pad_push_event (stream->pad, stream->pending_event);
4261 stream->pending_event = NULL;
4264 if (G_UNLIKELY (stream->subtype != FOURCC_text
4265 && stream->subtype != FOURCC_sbtl &&
4266 stream->subtype != FOURCC_subp)) {
4270 gst_buffer_map (buf, &map, GST_MAP_READ);
4272 /* empty buffer is sent to terminate previous subtitle */
4273 if (map.size <= 2) {
4274 gst_buffer_unmap (buf, &map);
4275 gst_buffer_unref (buf);
4278 if (stream->subtype == FOURCC_subp) {
4279 /* That's all the processing needed for subpictures */
4280 gst_buffer_unmap (buf, &map);
4284 nsize = GST_READ_UINT16_BE (map.data);
4285 nsize = MIN (nsize, map.size - 2);
4287 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
4290 /* takes care of UTF-8 validation or UTF-16 recognition,
4291 * no other encoding expected */
4292 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
4293 gst_buffer_unmap (buf, &map);
4295 gst_buffer_unref (buf);
4296 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
4298 /* this should not really happen unless the subtitle is corrupted */
4299 gst_buffer_unref (buf);
4303 /* FIXME ? convert optional subsequent style info to markup */
4308 /* Sets a buffer's attributes properly and pushes it downstream.
4309 * Also checks for additional actions and custom processing that may
4310 * need to be done first.
4312 static GstFlowReturn
4313 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
4314 QtDemuxStream * stream, GstBuffer * buf,
4315 GstClockTime dts, GstClockTime pts, GstClockTime duration,
4316 gboolean keyframe, GstClockTime position, guint64 byte_position)
4318 GstFlowReturn ret = GST_FLOW_OK;
4320 /* offset the timestamps according to the edit list */
4322 if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) {
4326 gst_buffer_map (buf, &map, GST_MAP_READ);
4327 url = g_strndup ((gchar *) map.data, map.size);
4328 gst_buffer_unmap (buf, &map);
4329 if (url != NULL && strlen (url) != 0) {
4330 /* we have RTSP redirect now */
4331 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
4332 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
4333 gst_structure_new ("redirect",
4334 "new-location", G_TYPE_STRING, url, NULL)));
4335 qtdemux->posted_redirect = TRUE;
4337 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
4343 /* position reporting */
4344 if (qtdemux->segment.rate >= 0) {
4345 qtdemux->segment.position = position;
4346 gst_qtdemux_sync_streams (qtdemux);
4349 if (G_UNLIKELY (!stream->pad)) {
4350 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
4351 gst_buffer_unref (buf);
4355 /* send out pending buffers */
4356 while (stream->buffers) {
4357 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
4359 if (G_UNLIKELY (stream->discont)) {
4360 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
4361 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
4362 stream->discont = FALSE;
4364 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
4367 gst_pad_push (stream->pad, buffer);
4369 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
4372 /* we're going to modify the metadata */
4373 buf = gst_buffer_make_writable (buf);
4375 if (G_UNLIKELY (stream->need_process))
4376 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
4382 GST_BUFFER_DTS (buf) = dts;
4383 GST_BUFFER_PTS (buf) = pts;
4384 GST_BUFFER_DURATION (buf) = duration;
4385 GST_BUFFER_OFFSET (buf) = -1;
4386 GST_BUFFER_OFFSET_END (buf) = -1;
4388 if (G_UNLIKELY (stream->rgb8_palette))
4389 gst_buffer_append_memory (buf, gst_memory_ref (stream->rgb8_palette));
4391 if (G_UNLIKELY (stream->padding)) {
4392 gst_buffer_resize (buf, stream->padding, -1);
4395 if (G_UNLIKELY (qtdemux->element_index)) {
4396 GstClockTime stream_time;
4399 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
4401 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
4402 GST_LOG_OBJECT (qtdemux,
4403 "adding association %" GST_TIME_FORMAT "-> %"
4404 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
4405 gst_index_add_association (qtdemux->element_index,
4407 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
4408 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
4409 GST_FORMAT_BYTES, byte_position, NULL);
4414 if (stream->need_clip)
4415 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
4417 if (G_UNLIKELY (buf == NULL))
4420 if (G_UNLIKELY (stream->discont)) {
4421 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
4422 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
4423 stream->discont = FALSE;
4425 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
4429 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
4430 stream->on_keyframe = FALSE;
4432 stream->on_keyframe = TRUE;
4436 GST_LOG_OBJECT (qtdemux,
4437 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
4438 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
4439 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
4440 GST_PAD_NAME (stream->pad));
4442 ret = gst_pad_push (stream->pad, buf);
4444 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
4445 /* mark position in stream, we'll need this to know when to send GAP event */
4446 stream->segment.position = pts + duration;
4453 static const QtDemuxRandomAccessEntry *
4454 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4455 GstClockTime pos, gboolean after)
4457 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
4458 guint n_entries = stream->n_ra_entries;
4461 /* we assume the table is sorted */
4462 for (i = 0; i < n_entries; ++i) {
4463 if (entries[i].ts > pos)
4467 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
4468 * probably okay to assume that the index lists the very first fragment */
4475 return &entries[i - 1];
4479 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
4481 const QtDemuxRandomAccessEntry *best_entry = NULL;
4484 GST_OBJECT_LOCK (qtdemux);
4486 g_assert (qtdemux->n_streams > 0);
4488 for (i = 0; i < qtdemux->n_streams; i++) {
4489 const QtDemuxRandomAccessEntry *entry;
4490 QtDemuxStream *stream;
4491 gboolean is_audio_or_video;
4493 stream = qtdemux->streams[i];
4495 g_free (stream->samples);
4496 stream->samples = NULL;
4497 stream->n_samples = 0;
4498 stream->stbl_index = -1; /* no samples have yet been parsed */
4499 stream->sample_index = -1;
4501 if (stream->ra_entries == NULL)
4504 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
4505 is_audio_or_video = TRUE;
4507 is_audio_or_video = FALSE;
4510 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
4511 stream->time_position, !is_audio_or_video);
4513 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
4514 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
4516 stream->pending_seek = entry;
4518 /* decide position to jump to just based on audio/video tracks, not subs */
4519 if (!is_audio_or_video)
4522 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
4526 if (best_entry == NULL) {
4527 GST_OBJECT_UNLOCK (qtdemux);
4531 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
4532 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
4533 GST_TIME_ARGS (qtdemux->streams[0]->time_position),
4534 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
4536 qtdemux->moof_offset = best_entry->moof_offset;
4538 qtdemux_add_fragmented_samples (qtdemux);
4540 GST_OBJECT_UNLOCK (qtdemux);
4544 static GstFlowReturn
4545 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
4547 GstFlowReturn ret = GST_FLOW_OK;
4548 GstBuffer *buf = NULL;
4549 QtDemuxStream *stream;
4550 GstClockTime min_time;
4552 GstClockTime dts = GST_CLOCK_TIME_NONE;
4553 GstClockTime pts = GST_CLOCK_TIME_NONE;
4554 GstClockTime duration = 0;
4555 gboolean keyframe = FALSE;
4556 guint sample_size = 0;
4562 gst_qtdemux_push_pending_newsegment (qtdemux);
4564 if (qtdemux->fragmented_seek_pending) {
4565 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
4566 gst_qtdemux_do_fragmented_seek (qtdemux);
4567 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
4568 qtdemux->fragmented_seek_pending = FALSE;
4571 /* Figure out the next stream sample to output, min_time is expressed in
4572 * global time and runs over the edit list segments. */
4573 min_time = G_MAXUINT64;
4575 for (i = 0; i < qtdemux->n_streams; i++) {
4576 GstClockTime position;
4578 stream = qtdemux->streams[i];
4579 position = stream->time_position;
4581 /* position of -1 is EOS */
4582 if (position != GST_CLOCK_TIME_NONE && position < min_time) {
4583 min_time = position;
4588 if (G_UNLIKELY (index == -1)) {
4589 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
4593 /* check for segment end */
4594 if (G_UNLIKELY (qtdemux->segment.stop != -1
4595 && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
4596 || (qtdemux->segment.rate < 0
4597 && qtdemux->segment.start > min_time))
4598 && qtdemux->streams[index]->on_keyframe)) {
4599 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
4600 qtdemux->streams[index]->time_position = GST_CLOCK_TIME_NONE;
4604 /* gap events for subtitle streams */
4605 for (i = 0; i < qtdemux->n_streams; i++) {
4606 stream = qtdemux->streams[i];
4607 if (stream->pad && (stream->subtype == FOURCC_subp
4608 || stream->subtype == FOURCC_text
4609 || stream->subtype == FOURCC_sbtl)) {
4610 /* send one second gap events until the stream catches up */
4611 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
4612 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
4613 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
4614 stream->segment.position + GST_SECOND < min_time) {
4616 gst_event_new_gap (stream->segment.position, GST_SECOND);
4617 gst_pad_push_event (stream->pad, gap);
4618 stream->segment.position += GST_SECOND;
4623 stream = qtdemux->streams[index];
4624 if (stream->new_caps) {
4625 gst_qtdemux_configure_stream (qtdemux, stream);
4626 qtdemux_do_allocation (qtdemux, stream);
4629 /* fetch info for the current sample of this stream */
4630 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
4631 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
4634 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
4635 if (G_UNLIKELY (qtdemux->
4636 segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
4637 if (stream->subtype == FOURCC_vide && !keyframe) {
4638 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on stream %d", index);
4643 GST_DEBUG_OBJECT (qtdemux,
4644 "pushing from stream %d, empty %d offset %" G_GUINT64_FORMAT
4645 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
4646 ", duration %" GST_TIME_FORMAT, index, empty, offset, sample_size,
4647 GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
4649 if (G_UNLIKELY (empty)) {
4650 /* empty segment, push a gap and move to the next one */
4651 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
4652 stream->segment.position = pts + duration;
4656 /* hmm, empty sample, skip and move to next sample */
4657 if (G_UNLIKELY (sample_size <= 0))
4660 /* last pushed sample was out of boundary, goto next sample */
4661 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
4664 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
4667 GST_DEBUG_OBJECT (qtdemux,
4668 "size %d larger than stream max_buffer_size %d, trimming",
4669 sample_size, stream->max_buffer_size);
4671 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
4674 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
4677 if (stream->use_allocator) {
4678 /* if we have a per-stream allocator, use it */
4679 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
4682 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
4684 if (G_UNLIKELY (ret != GST_FLOW_OK))
4687 if (size != sample_size) {
4688 pts += gst_util_uint64_scale_int (GST_SECOND,
4689 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
4690 dts += gst_util_uint64_scale_int (GST_SECOND,
4691 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
4692 duration = gst_util_uint64_scale_int (GST_SECOND,
4693 size / stream->bytes_per_frame, stream->timescale);
4696 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
4697 dts, pts, duration, keyframe, min_time, offset);
4699 if (size != sample_size) {
4700 QtDemuxSample *sample = &stream->samples[stream->sample_index];
4701 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
4703 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
4704 sample->timestamp + stream->offset_in_sample / stream->bytes_per_frame);
4705 if (time_position >= segment->media_start) {
4706 /* inside the segment, update time_position, looks very familiar to
4707 * GStreamer segments, doesn't it? */
4708 stream->time_position = (time_position - segment->media_start) +
4711 /* not yet in segment, time does not yet increment. This means
4712 * that we are still prerolling keyframes to the decoder so it can
4713 * decode the first sample of the segment. */
4714 stream->time_position = segment->time;
4719 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
4720 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
4721 * we have no more data for the pad to push */
4722 if (ret == GST_FLOW_EOS)
4725 stream->offset_in_sample += size;
4726 if (stream->offset_in_sample >= sample_size) {
4727 gst_qtdemux_advance_sample (qtdemux, stream);
4732 gst_qtdemux_advance_sample (qtdemux, stream);
4740 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
4746 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
4747 /* EOS will be raised if all are EOS */
4754 gst_qtdemux_loop (GstPad * pad)
4756 GstQTDemux *qtdemux;
4760 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
4762 cur_offset = qtdemux->offset;
4763 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %d",
4764 cur_offset, qtdemux->state);
4766 switch (qtdemux->state) {
4767 case QTDEMUX_STATE_INITIAL:
4768 case QTDEMUX_STATE_HEADER:
4769 ret = gst_qtdemux_loop_state_header (qtdemux);
4771 case QTDEMUX_STATE_MOVIE:
4772 ret = gst_qtdemux_loop_state_movie (qtdemux);
4773 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
4774 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
4782 /* if something went wrong, pause */
4783 if (ret != GST_FLOW_OK)
4787 gst_object_unref (qtdemux);
4793 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
4794 (NULL), ("streaming stopped, invalid state"));
4795 gst_pad_pause_task (pad);
4796 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
4801 const gchar *reason = gst_flow_get_name (ret);
4803 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
4805 gst_pad_pause_task (pad);
4807 /* fatal errors need special actions */
4809 if (ret == GST_FLOW_EOS) {
4810 if (qtdemux->n_streams == 0) {
4811 /* we have no streams, post an error */
4812 gst_qtdemux_post_no_playable_stream_error (qtdemux);
4814 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
4817 if ((stop = qtdemux->segment.stop) == -1)
4818 stop = qtdemux->segment.duration;
4820 if (qtdemux->segment.rate >= 0) {
4821 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
4822 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
4823 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
4824 GST_FORMAT_TIME, stop));
4825 gst_qtdemux_push_event (qtdemux,
4826 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
4828 /* For Reverse Playback */
4829 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
4830 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
4831 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
4832 GST_FORMAT_TIME, qtdemux->segment.start));
4833 gst_qtdemux_push_event (qtdemux,
4834 gst_event_new_segment_done (GST_FORMAT_TIME,
4835 qtdemux->segment.start));
4838 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
4839 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
4841 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
4842 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
4843 (NULL), ("streaming stopped, reason %s", reason));
4844 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
4853 * Returns if there are samples to be played.
4856 has_next_entry (GstQTDemux * demux)
4858 QtDemuxStream *stream;
4861 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
4863 for (i = 0; i < demux->n_streams; i++) {
4864 stream = demux->streams[i];
4866 if (stream->sample_index == -1) {
4867 stream->sample_index = 0;
4868 stream->offset_in_sample = 0;
4871 if (stream->sample_index >= stream->n_samples) {
4872 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
4875 GST_DEBUG_OBJECT (demux, "Found a sample");
4879 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
4886 * Returns the size of the first entry at the current offset.
4887 * If -1, there are none (which means EOS or empty file).
4890 next_entry_size (GstQTDemux * demux)
4892 QtDemuxStream *stream;
4895 guint64 smalloffs = (guint64) - 1;
4896 QtDemuxSample *sample;
4898 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
4901 for (i = 0; i < demux->n_streams; i++) {
4902 stream = demux->streams[i];
4904 if (stream->sample_index == -1) {
4905 stream->sample_index = 0;
4906 stream->offset_in_sample = 0;
4909 if (stream->sample_index >= stream->n_samples) {
4910 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
4914 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
4915 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
4916 stream->sample_index);
4920 sample = &stream->samples[stream->sample_index];
4922 GST_LOG_OBJECT (demux,
4923 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
4924 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
4925 sample->offset, sample->size);
4927 if (((smalloffs == -1)
4928 || (sample->offset < smalloffs)) && (sample->size)) {
4930 smalloffs = sample->offset;
4934 GST_LOG_OBJECT (demux,
4935 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
4936 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
4941 stream = demux->streams[smallidx];
4942 sample = &stream->samples[stream->sample_index];
4944 if (sample->offset >= demux->offset) {
4945 demux->todrop = sample->offset - demux->offset;
4946 return sample->size + demux->todrop;
4949 GST_DEBUG_OBJECT (demux,
4950 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
4955 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
4957 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
4959 gst_element_post_message (GST_ELEMENT_CAST (demux),
4960 gst_message_new_element (GST_OBJECT_CAST (demux),
4961 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
4965 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
4970 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
4973 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
4974 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
4975 GST_SEEK_TYPE_NONE, -1);
4977 res = gst_pad_push_event (demux->sinkpad, event);
4982 /* check for seekable upstream, above and beyond a mere query */
4984 gst_qtdemux_check_seekability (GstQTDemux * demux)
4987 gboolean seekable = FALSE;
4988 gint64 start = -1, stop = -1;
4990 if (demux->upstream_size)
4993 query = gst_query_new_seeking (GST_FORMAT_BYTES);
4994 if (!gst_pad_peer_query (demux->sinkpad, query)) {
4995 GST_DEBUG_OBJECT (demux, "seeking query failed");
4999 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
5001 /* try harder to query upstream size if we didn't get it the first time */
5002 if (seekable && stop == -1) {
5003 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
5004 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
5007 /* if upstream doesn't know the size, it's likely that it's not seekable in
5008 * practice even if it technically may be seekable */
5009 if (seekable && (start != 0 || stop <= start)) {
5010 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
5015 gst_query_unref (query);
5017 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
5018 G_GUINT64_FORMAT ")", seekable, start, stop);
5019 demux->upstream_seekable = seekable;
5020 demux->upstream_size = seekable ? stop : -1;
5024 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
5026 g_return_if_fail (bytes <= demux->todrop);
5028 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
5029 gst_adapter_flush (demux->adapter, bytes);
5030 demux->neededbytes -= bytes;
5031 demux->offset += bytes;
5032 demux->todrop -= bytes;
5035 static GstFlowReturn
5036 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
5040 demux = GST_QTDEMUX (parent);
5042 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
5045 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
5047 for (i = 0; i < demux->n_streams; i++) {
5048 demux->streams[i]->discont = TRUE;
5051 /* Reverse fragmented playback, need to flush all we have before
5052 * consuming a new fragment.
5053 * The samples array have the timestamps calculated by accumulating the
5054 * durations but this won't work for reverse playback of fragments as
5055 * the timestamps of a subsequent fragment should be smaller than the
5056 * previously received one. */
5057 if (demux->fragmented && demux->segment.rate < 0) {
5058 gst_qtdemux_process_adapter (demux, TRUE);
5059 for (i = 0; i < demux->n_streams; i++)
5060 gst_qtdemux_stream_flush_samples_data (demux, demux->streams[i]);
5064 gst_adapter_push (demux->adapter, inbuf);
5066 GST_DEBUG_OBJECT (demux,
5067 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
5068 demux->neededbytes, gst_adapter_available (demux->adapter));
5070 return gst_qtdemux_process_adapter (demux, FALSE);
5073 static GstFlowReturn
5074 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
5076 GstFlowReturn ret = GST_FLOW_OK;
5078 /* we never really mean to buffer that much */
5079 if (demux->neededbytes == -1) {
5083 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
5084 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
5086 GST_DEBUG_OBJECT (demux,
5087 "state:%d , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT,
5088 demux->state, demux->neededbytes, demux->offset);
5090 switch (demux->state) {
5091 case QTDEMUX_STATE_INITIAL:{
5096 gst_qtdemux_check_seekability (demux);
5098 data = gst_adapter_map (demux->adapter, demux->neededbytes);
5100 /* get fourcc/length, set neededbytes */
5101 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
5103 gst_adapter_unmap (demux->adapter);
5105 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
5106 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
5108 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
5109 (_("This file is invalid and cannot be played.")),
5110 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
5111 GST_FOURCC_ARGS (fourcc)));
5112 ret = GST_FLOW_ERROR;
5115 if (fourcc == FOURCC_mdat) {
5116 gint next_entry = next_entry_size (demux);
5117 if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
5118 /* we have the headers, start playback */
5119 demux->state = QTDEMUX_STATE_MOVIE;
5120 demux->neededbytes = next_entry;
5121 demux->mdatleft = size;
5123 /* no headers yet, try to get them */
5126 guint64 old, target;
5129 old = demux->offset;
5130 target = old + size;
5132 /* try to jump over the atom with a seek */
5133 /* only bother if it seems worth doing so,
5134 * and avoids possible upstream/server problems */
5135 if (demux->upstream_seekable &&
5136 demux->upstream_size > 4 * (1 << 20)) {
5137 res = qtdemux_seek_offset (demux, target);
5139 GST_DEBUG_OBJECT (demux, "skipping seek");
5144 GST_DEBUG_OBJECT (demux, "seek success");
5145 /* remember the offset fo the first mdat so we can seek back to it
5146 * after we have the headers */
5147 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
5148 demux->first_mdat = old;
5149 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
5152 /* seek worked, continue reading */
5153 demux->offset = target;
5154 demux->neededbytes = 16;
5155 demux->state = QTDEMUX_STATE_INITIAL;
5157 /* seek failed, need to buffer */
5158 demux->offset = old;
5159 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
5160 /* there may be multiple mdat (or alike) buffers */
5162 if (demux->mdatbuffer)
5163 bs = gst_buffer_get_size (demux->mdatbuffer);
5166 if (size + bs > 10 * (1 << 20))
5168 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
5169 demux->neededbytes = size;
5170 if (!demux->mdatbuffer)
5171 demux->mdatoffset = demux->offset;
5174 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
5175 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
5176 (_("This file is invalid and cannot be played.")),
5177 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
5178 GST_FOURCC_ARGS (fourcc), size));
5179 ret = GST_FLOW_ERROR;
5182 /* this means we already started buffering and still no moov header,
5183 * let's continue buffering everything till we get moov */
5184 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
5185 || fourcc == FOURCC_moof))
5187 demux->neededbytes = size;
5188 demux->state = QTDEMUX_STATE_HEADER;
5192 case QTDEMUX_STATE_HEADER:{
5196 GST_DEBUG_OBJECT (demux, "In header");
5198 data = gst_adapter_map (demux->adapter, demux->neededbytes);
5200 /* parse the header */
5201 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
5203 if (fourcc == FOURCC_moov) {
5204 /* in usual fragmented setup we could try to scan for more
5205 * and end up at the the moov (after mdat) again */
5206 if (demux->got_moov && demux->n_streams > 0 &&
5208 || demux->last_moov_offset == demux->offset)) {
5209 GST_DEBUG_OBJECT (demux,
5210 "Skipping moov atom as we have (this) one already");
5212 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
5214 if (demux->got_moov && demux->fragmented) {
5215 GST_DEBUG_OBJECT (demux,
5216 "Got a second moov, clean up data from old one");
5217 if (demux->moov_node)
5218 g_node_destroy (demux->moov_node);
5219 demux->moov_node = NULL;
5220 demux->moov_node_compressed = NULL;
5222 /* prepare newsegment to send when streaming actually starts */
5223 if (!demux->pending_newsegment)
5224 demux->pending_newsegment =
5225 gst_event_new_segment (&demux->segment);
5228 demux->last_moov_offset = demux->offset;
5230 qtdemux_parse_moov (demux, data, demux->neededbytes);
5231 qtdemux_node_dump (demux, demux->moov_node);
5232 qtdemux_parse_tree (demux);
5233 qtdemux_prepare_streams (demux);
5234 if (!demux->got_moov)
5235 qtdemux_expose_streams (demux);
5239 for (n = 0; n < demux->n_streams; n++) {
5240 QtDemuxStream *stream = demux->streams[n];
5242 gst_qtdemux_configure_stream (demux, stream);
5246 demux->got_moov = TRUE;
5248 g_node_destroy (demux->moov_node);
5249 demux->moov_node = NULL;
5250 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
5252 } else if (fourcc == FOURCC_moof) {
5253 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
5255 GstClockTime prev_pts;
5256 guint64 prev_offset;
5258 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
5261 * The timestamp of the moof buffer is relevant as some scenarios
5262 * won't have the initial timestamp in the atoms. Whenever a new
5263 * buffer has started, we get that buffer's PTS and use it as a base
5264 * timestamp for the trun entries.
5266 * To keep track of the current buffer timestamp and starting point
5267 * we use gst_adapter_prev_pts that gives us the PTS and the distance
5268 * from the beggining of the buffer, with the distance and demux->offset
5269 * we know if it is still the same buffer or not.
5271 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
5272 prev_offset = demux->offset - dist;
5273 if (demux->fragment_start_offset == -1
5274 || prev_offset > demux->fragment_start_offset) {
5275 demux->fragment_start_offset = prev_offset;
5276 demux->fragment_start = prev_pts;
5277 GST_DEBUG_OBJECT (demux,
5278 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
5279 GST_TIME_FORMAT, demux->fragment_start_offset,
5280 GST_TIME_ARGS (demux->fragment_start));
5283 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
5284 demux->offset, NULL)) {
5285 gst_adapter_unmap (demux->adapter);
5286 ret = GST_FLOW_ERROR;
5289 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
5290 if (demux->mss_mode && !demux->exposed) {
5291 if (!demux->pending_newsegment) {
5293 gst_segment_init (&segment, GST_FORMAT_TIME);
5294 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
5295 demux->pending_newsegment = gst_event_new_segment (&segment);
5297 qtdemux_expose_streams (demux);
5300 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
5302 } else if (fourcc == FOURCC_ftyp) {
5303 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
5304 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
5305 } else if (fourcc == FOURCC_uuid) {
5306 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
5307 qtdemux_parse_uuid (demux, data, demux->neededbytes);
5308 } else if (fourcc == FOURCC_sidx) {
5309 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
5310 qtdemux_parse_sidx (demux, data, demux->neededbytes);
5312 GST_WARNING_OBJECT (demux,
5313 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
5314 GST_FOURCC_ARGS (fourcc));
5315 /* Let's jump that one and go back to initial state */
5317 gst_adapter_unmap (demux->adapter);
5320 if (demux->mdatbuffer && demux->n_streams) {
5321 gsize remaining_data_size = 0;
5323 /* the mdat was before the header */
5324 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
5325 demux->n_streams, demux->mdatbuffer);
5326 /* restore our adapter/offset view of things with upstream;
5327 * put preceding buffered data ahead of current moov data.
5328 * This should also handle evil mdat, moov, mdat cases and alike */
5329 gst_adapter_flush (demux->adapter, demux->neededbytes);
5331 /* Store any remaining data after the mdat for later usage */
5332 remaining_data_size = gst_adapter_available (demux->adapter);
5333 if (remaining_data_size > 0) {
5334 g_assert (demux->restoredata_buffer == NULL);
5335 demux->restoredata_buffer =
5336 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
5337 demux->restoredata_offset = demux->offset + demux->neededbytes;
5338 GST_DEBUG_OBJECT (demux,
5339 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
5340 G_GUINT64_FORMAT, remaining_data_size,
5341 demux->restoredata_offset);
5344 gst_adapter_push (demux->adapter, demux->mdatbuffer);
5345 demux->mdatbuffer = NULL;
5346 demux->offset = demux->mdatoffset;
5347 demux->neededbytes = next_entry_size (demux);
5348 demux->state = QTDEMUX_STATE_MOVIE;
5349 demux->mdatleft = gst_adapter_available (demux->adapter);
5351 GST_DEBUG_OBJECT (demux, "Carrying on normally");
5352 gst_adapter_flush (demux->adapter, demux->neededbytes);
5354 /* only go back to the mdat if there are samples to play */
5355 if (demux->got_moov && demux->first_mdat != -1
5356 && has_next_entry (demux)) {
5359 /* we need to seek back */
5360 res = qtdemux_seek_offset (demux, demux->first_mdat);
5362 demux->offset = demux->first_mdat;
5364 GST_DEBUG_OBJECT (demux, "Seek back failed");
5367 demux->offset += demux->neededbytes;
5369 demux->neededbytes = 16;
5370 demux->state = QTDEMUX_STATE_INITIAL;
5375 case QTDEMUX_STATE_BUFFER_MDAT:{
5379 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
5381 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
5382 gst_buffer_extract (buf, 0, fourcc, 4);
5383 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
5384 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
5385 if (demux->mdatbuffer)
5386 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
5388 demux->mdatbuffer = buf;
5389 demux->offset += demux->neededbytes;
5390 demux->neededbytes = 16;
5391 demux->state = QTDEMUX_STATE_INITIAL;
5392 gst_qtdemux_post_progress (demux, 1, 1);
5396 case QTDEMUX_STATE_MOVIE:{
5397 QtDemuxStream *stream = NULL;
5398 QtDemuxSample *sample;
5400 GstClockTime dts, pts, duration;
5403 GST_DEBUG_OBJECT (demux,
5404 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
5406 if (demux->fragmented) {
5407 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
5409 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
5410 /* if needed data starts within this atom,
5411 * then it should not exceed this atom */
5412 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
5413 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
5414 (_("This file is invalid and cannot be played.")),
5415 ("sample data crosses atom boundary"));
5416 ret = GST_FLOW_ERROR;
5419 demux->mdatleft -= demux->neededbytes;
5421 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
5422 /* so we are dropping more than left in this atom */
5423 gst_qtdemux_drop_data (demux, demux->mdatleft);
5424 demux->mdatleft = 0;
5426 /* need to resume atom parsing so we do not miss any other pieces */
5427 demux->state = QTDEMUX_STATE_INITIAL;
5428 demux->neededbytes = 16;
5430 /* check if there was any stored post mdat data from previous buffers */
5431 if (demux->restoredata_buffer) {
5432 g_assert (gst_adapter_available (demux->adapter) == 0);
5434 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
5435 demux->restoredata_buffer = NULL;
5436 demux->offset = demux->restoredata_offset;
5443 if (demux->todrop) {
5444 gst_qtdemux_drop_data (demux, demux->todrop);
5448 /* initial newsegment sent here after having added pads,
5449 * possible others in sink_event */
5450 if (G_UNLIKELY (demux->pending_newsegment)) {
5451 gst_qtdemux_push_pending_newsegment (demux);
5452 /* clear to send tags on all streams */
5453 for (i = 0; i < demux->n_streams; i++) {
5454 stream = demux->streams[i];
5455 gst_qtdemux_push_tags (demux, stream);
5456 if (stream->sparse) {
5457 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
5458 gst_pad_push_event (stream->pad,
5459 gst_event_new_gap (stream->segment.position,
5460 GST_CLOCK_TIME_NONE));
5465 /* Figure out which stream this packet belongs to */
5466 for (i = 0; i < demux->n_streams; i++) {
5467 stream = demux->streams[i];
5468 if (stream->sample_index >= stream->n_samples)
5470 GST_LOG_OBJECT (demux,
5471 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
5472 " / size:%d)", i, stream->sample_index,
5473 stream->samples[stream->sample_index].offset,
5474 stream->samples[stream->sample_index].size);
5476 if (stream->samples[stream->sample_index].offset == demux->offset)
5480 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
5481 goto unknown_stream;
5483 if (stream->new_caps) {
5484 gst_qtdemux_configure_stream (demux, stream);
5487 /* Put data in a buffer, set timestamps, caps, ... */
5488 sample = &stream->samples[stream->sample_index];
5490 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
5491 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
5492 GST_FOURCC_ARGS (stream->fourcc));
5494 dts = QTSAMPLE_DTS (stream, sample);
5495 pts = QTSAMPLE_PTS (stream, sample);
5496 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
5497 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5499 /* check for segment end */
5500 if (G_UNLIKELY (demux->segment.stop != -1
5501 && demux->segment.stop <= pts && stream->on_keyframe)) {
5502 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
5503 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
5505 /* skip this data, stream is EOS */
5506 gst_adapter_flush (demux->adapter, demux->neededbytes);
5508 /* check if all streams are eos */
5510 for (i = 0; i < demux->n_streams; i++) {
5511 if (!STREAM_IS_EOS (demux->streams[i])) {
5517 if (ret == GST_FLOW_EOS) {
5518 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
5525 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
5527 /* FIXME: should either be an assert or a plain check */
5528 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
5530 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
5531 dts, pts, duration, keyframe, dts, demux->offset);
5535 ret = gst_qtdemux_combine_flows (demux, stream, ret);
5537 /* skip this data, stream is EOS */
5538 gst_adapter_flush (demux->adapter, demux->neededbytes);
5541 stream->sample_index++;
5542 stream->offset_in_sample = 0;
5544 /* update current offset and figure out size of next buffer */
5545 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
5546 demux->offset, demux->neededbytes);
5547 demux->offset += demux->neededbytes;
5548 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
5551 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
5552 if (demux->fragmented) {
5553 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
5554 /* there may be more to follow, only finish this atom */
5555 demux->todrop = demux->mdatleft;
5556 demux->neededbytes = demux->todrop;
5568 /* when buffering movie data, at least show user something is happening */
5569 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
5570 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
5571 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
5572 demux->neededbytes);
5581 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
5582 ret = GST_FLOW_ERROR;
5587 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
5593 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
5594 (NULL), ("qtdemuxer invalid state %d", demux->state));
5595 ret = GST_FLOW_ERROR;
5600 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
5601 (NULL), ("no 'moov' atom within the first 10 MB"));
5602 ret = GST_FLOW_ERROR;
5608 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
5613 query = gst_query_new_scheduling ();
5615 if (!gst_pad_peer_query (sinkpad, query)) {
5616 gst_query_unref (query);
5620 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
5621 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
5622 gst_query_unref (query);
5627 GST_DEBUG_OBJECT (sinkpad, "activating pull");
5628 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
5632 GST_DEBUG_OBJECT (sinkpad, "activating push");
5633 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
5638 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
5639 GstPadMode mode, gboolean active)
5642 GstQTDemux *demux = GST_QTDEMUX (parent);
5645 case GST_PAD_MODE_PUSH:
5646 demux->pullbased = FALSE;
5649 case GST_PAD_MODE_PULL:
5651 demux->pullbased = TRUE;
5652 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
5655 res = gst_pad_stop_task (sinkpad);
5667 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
5669 return g_malloc (items * size);
5673 qtdemux_zfree (void *opaque, void *addr)
5679 qtdemux_inflate (void *z_buffer, guint z_length, guint length)
5685 z = g_new0 (z_stream, 1);
5686 z->zalloc = qtdemux_zalloc;
5687 z->zfree = qtdemux_zfree;
5690 z->next_in = z_buffer;
5691 z->avail_in = z_length;
5693 buffer = (guint8 *) g_malloc (length);
5694 ret = inflateInit (z);
5695 while (z->avail_in > 0) {
5696 if (z->avail_out == 0) {
5698 buffer = (guint8 *) g_realloc (buffer, length);
5699 z->next_out = buffer + z->total_out;
5700 z->avail_out = 1024;
5702 ret = inflate (z, Z_SYNC_FLUSH);
5706 if (ret != Z_STREAM_END) {
5707 g_warning ("inflate() returned %d", ret);
5713 #endif /* HAVE_ZLIB */
5716 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
5720 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
5722 /* counts as header data */
5723 qtdemux->header_size += length;
5725 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
5726 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
5728 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
5734 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
5735 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
5736 if (dcom == NULL || cmvd == NULL)
5737 goto invalid_compression;
5739 method = QT_FOURCC ((guint8 *) dcom->data + 8);
5742 case GST_MAKE_FOURCC ('z', 'l', 'i', 'b'):{
5743 guint uncompressed_length;
5744 guint compressed_length;
5747 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
5748 compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12;
5749 GST_LOG ("length = %u", uncompressed_length);
5752 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
5753 compressed_length, uncompressed_length);
5755 qtdemux->moov_node_compressed = qtdemux->moov_node;
5756 qtdemux->moov_node = g_node_new (buf);
5758 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
5759 uncompressed_length);
5762 #endif /* HAVE_ZLIB */
5764 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
5765 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
5772 invalid_compression:
5774 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
5780 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
5783 while (G_UNLIKELY (buf < end)) {
5787 if (G_UNLIKELY (buf + 4 > end)) {
5788 GST_LOG_OBJECT (qtdemux, "buffer overrun");
5791 len = QT_UINT32 (buf);
5792 if (G_UNLIKELY (len == 0)) {
5793 GST_LOG_OBJECT (qtdemux, "empty container");
5796 if (G_UNLIKELY (len < 8)) {
5797 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
5800 if (G_UNLIKELY (len > (end - buf))) {
5801 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
5802 (gint) (end - buf));
5806 child = g_node_new ((guint8 *) buf);
5807 g_node_append (node, child);
5808 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
5809 qtdemux_parse_node (qtdemux, child, buf, len);
5817 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
5820 int len = QT_UINT32 (xdxt->data);
5821 guint8 *buf = xdxt->data;
5822 guint8 *end = buf + len;
5825 /* skip size and type */
5833 size = QT_UINT32 (buf);
5834 type = QT_FOURCC (buf + 4);
5836 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
5838 if (buf + size > end || size <= 0)
5844 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
5845 GST_FOURCC_ARGS (type));
5849 buffer = gst_buffer_new_and_alloc (size);
5850 gst_buffer_fill (buffer, 0, buf, size);
5851 stream->buffers = g_slist_append (stream->buffers, buffer);
5852 GST_LOG_OBJECT (qtdemux, "parsing theora header");
5855 buffer = gst_buffer_new_and_alloc (size);
5856 gst_buffer_fill (buffer, 0, buf, size);
5857 stream->buffers = g_slist_append (stream->buffers, buffer);
5858 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
5861 buffer = gst_buffer_new_and_alloc (size);
5862 gst_buffer_fill (buffer, 0, buf, size);
5863 stream->buffers = g_slist_append (stream->buffers, buffer);
5864 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
5867 GST_WARNING_OBJECT (qtdemux,
5868 "unknown theora cookie %" GST_FOURCC_FORMAT,
5869 GST_FOURCC_ARGS (type));
5878 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
5882 guint32 node_length = 0;
5883 const QtNodeType *type;
5886 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
5888 if (G_UNLIKELY (length < 8))
5889 goto not_enough_data;
5891 node_length = QT_UINT32 (buffer);
5892 fourcc = QT_FOURCC (buffer + 4);
5894 /* ignore empty nodes */
5895 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
5898 type = qtdemux_type_get (fourcc);
5900 end = buffer + length;
5902 GST_LOG_OBJECT (qtdemux,
5903 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
5904 GST_FOURCC_ARGS (fourcc), node_length, type->name);
5906 if (node_length > length)
5907 goto broken_atom_size;
5909 if (type->flags & QT_FLAG_CONTAINER) {
5910 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
5915 if (node_length < 20) {
5916 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
5919 GST_DEBUG_OBJECT (qtdemux,
5920 "parsing stsd (sample table, sample description) atom");
5921 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
5922 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
5932 /* also read alac (or whatever) in stead of mp4a in the following,
5933 * since a similar layout is used in other cases as well */
5934 if (fourcc == FOURCC_mp4a)
5939 /* There are two things we might encounter here: a true mp4a atom, and
5940 an mp4a entry in an stsd atom. The latter is what we're interested
5941 in, and it looks like an atom, but isn't really one. The true mp4a
5942 atom is short, so we detect it based on length here. */
5943 if (length < min_size) {
5944 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
5945 GST_FOURCC_ARGS (fourcc));
5949 /* 'version' here is the sound sample description version. Types 0 and
5950 1 are documented in the QTFF reference, but type 2 is not: it's
5951 described in Apple header files instead (struct SoundDescriptionV2
5953 version = QT_UINT16 (buffer + 16);
5955 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
5956 GST_FOURCC_ARGS (fourcc), version);
5958 /* parse any esds descriptors */
5970 GST_WARNING_OBJECT (qtdemux,
5971 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
5972 GST_FOURCC_ARGS (fourcc), version);
5977 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
5994 /* codec_data is contained inside these atoms, which all have
5995 * the same format. */
5997 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
5998 GST_FOURCC_ARGS (fourcc));
5999 version = QT_UINT32 (buffer + 16);
6000 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
6001 if (1 || version == 0x00000000) {
6002 buf = buffer + 0x32;
6004 /* FIXME Quicktime uses PASCAL string while
6005 * the iso format uses C strings. Check the file
6006 * type before attempting to parse the string here. */
6007 tlen = QT_UINT8 (buf);
6008 GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
6010 GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
6011 /* the string has a reserved space of 32 bytes so skip
6012 * the remaining 31 */
6014 buf += 4; /* and 4 bytes reserved */
6016 GST_MEMDUMP_OBJECT (qtdemux, "mp4v", buf, end - buf);
6018 qtdemux_parse_container (qtdemux, node, buf, end);
6024 GST_MEMDUMP_OBJECT (qtdemux, "H264", buffer, end - buffer);
6025 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6030 GST_MEMDUMP_OBJECT (qtdemux, "avc1", buffer, end - buffer);
6031 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6036 GST_MEMDUMP_OBJECT (qtdemux, "avc3", buffer, end - buffer);
6037 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6042 GST_MEMDUMP_OBJECT (qtdemux, "H265", buffer, end - buffer);
6043 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6048 GST_MEMDUMP_OBJECT (qtdemux, "hvc1", buffer, end - buffer);
6049 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6054 GST_MEMDUMP_OBJECT (qtdemux, "hev1", buffer, end - buffer);
6055 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6060 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
6065 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
6066 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
6071 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
6072 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
6073 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
6081 version = QT_UINT32 (buffer + 12);
6082 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
6089 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
6094 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
6099 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
6104 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
6108 if (!strcmp (type->name, "unknown"))
6109 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
6113 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
6114 GST_FOURCC_ARGS (fourcc));
6120 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
6121 (_("This file is corrupt and cannot be played.")),
6122 ("Not enough data for an atom header, got only %u bytes", length));
6127 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
6128 (_("This file is corrupt and cannot be played.")),
6129 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
6130 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
6137 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
6141 guint32 child_fourcc;
6143 for (child = g_node_first_child (node); child;
6144 child = g_node_next_sibling (child)) {
6145 buffer = (guint8 *) child->data;
6147 child_fourcc = QT_FOURCC (buffer + 4);
6149 if (G_UNLIKELY (child_fourcc == fourcc)) {
6157 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
6158 GstByteReader * parser)
6162 guint32 child_fourcc, child_len;
6164 for (child = g_node_first_child (node); child;
6165 child = g_node_next_sibling (child)) {
6166 buffer = (guint8 *) child->data;
6168 child_len = QT_UINT32 (buffer);
6169 child_fourcc = QT_FOURCC (buffer + 4);
6171 if (G_UNLIKELY (child_fourcc == fourcc)) {
6172 if (G_UNLIKELY (child_len < (4 + 4)))
6174 /* FIXME: must verify if atom length < parent atom length */
6175 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
6183 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
6184 GstByteReader * parser)
6188 guint32 child_fourcc, child_len;
6190 for (child = g_node_next_sibling (node); child;
6191 child = g_node_next_sibling (child)) {
6192 buffer = (guint8 *) child->data;
6194 child_fourcc = QT_FOURCC (buffer + 4);
6196 if (child_fourcc == fourcc) {
6198 child_len = QT_UINT32 (buffer);
6199 if (G_UNLIKELY (child_len < (4 + 4)))
6201 /* FIXME: must verify if atom length < parent atom length */
6202 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
6211 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
6213 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
6217 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
6219 /* FIXME: This can only reliably work if demuxers have a
6220 * separate streaming thread per srcpad. This should be
6221 * done in a demuxer base class, which integrates parts
6224 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
6229 query = gst_query_new_allocation (stream->caps, FALSE);
6231 if (!gst_pad_peer_query (stream->pad, query)) {
6232 /* not a problem, just debug a little */
6233 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
6236 if (stream->allocator)
6237 gst_object_unref (stream->allocator);
6239 if (gst_query_get_n_allocation_params (query) > 0) {
6240 /* try the allocator */
6241 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
6243 stream->use_allocator = TRUE;
6245 stream->allocator = NULL;
6246 gst_allocation_params_init (&stream->params);
6247 stream->use_allocator = FALSE;
6249 gst_query_unref (query);
6254 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
6256 if (stream->subtype == FOURCC_vide) {
6257 /* fps is calculated base on the duration of the average framerate since
6258 * qt does not have a fixed framerate. */
6259 if ((stream->n_samples == 1) && (stream->first_duration == 0)) {
6264 if (stream->duration == 0 || stream->n_samples < 2) {
6265 stream->fps_n = stream->timescale;
6268 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
6269 /* stream->duration is guint64, timescale, n_samples are guint32 */
6270 GstClockTime avg_duration =
6271 gst_util_uint64_scale_round (stream->duration -
6272 stream->first_duration, GST_SECOND,
6273 (guint64) (stream->timescale) * (stream->n_samples - 1));
6275 GST_LOG_OBJECT (qtdemux,
6276 "Calculating avg sample duration based on stream duration %"
6278 " minus first sample %u, leaving %d samples gives %"
6279 GST_TIME_FORMAT, stream->duration, stream->first_duration,
6280 stream->n_samples - 1, GST_TIME_ARGS (avg_duration));
6282 gst_video_guess_framerate (avg_duration, &stream->fps_n,
6285 GST_DEBUG_OBJECT (qtdemux,
6286 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
6287 stream->timescale, stream->fps_n, stream->fps_d);
6291 stream->caps = gst_caps_make_writable (stream->caps);
6293 gst_caps_set_simple (stream->caps,
6294 "width", G_TYPE_INT, stream->width,
6295 "height", G_TYPE_INT, stream->height,
6296 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
6298 /* calculate pixel-aspect-ratio using display width and height */
6299 GST_DEBUG_OBJECT (qtdemux,
6300 "video size %dx%d, target display size %dx%d", stream->width,
6301 stream->height, stream->display_width, stream->display_height);
6302 /* qt file might have pasp atom */
6303 if (stream->par_w > 0 && stream->par_h > 0) {
6304 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
6305 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
6306 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
6307 } else if (stream->display_width > 0 && stream->display_height > 0 &&
6308 stream->width > 0 && stream->height > 0) {
6311 /* calculate the pixel aspect ratio using the display and pixel w/h */
6312 n = stream->display_width * stream->height;
6313 d = stream->display_height * stream->width;
6316 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
6319 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
6320 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
6323 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
6324 guint par_w = 1, par_h = 1;
6326 if (stream->par_w > 0 && stream->par_h > 0) {
6327 par_w = stream->par_w;
6328 par_h = stream->par_h;
6331 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
6332 stream->width, stream->height, par_w, par_h)) {
6333 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
6336 gst_caps_set_simple (stream->caps,
6337 "multiview-mode", G_TYPE_STRING,
6338 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
6339 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
6340 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
6345 else if (stream->subtype == FOURCC_soun) {
6347 stream->caps = gst_caps_make_writable (stream->caps);
6348 if (stream->rate > 0)
6349 gst_caps_set_simple (stream->caps,
6350 "rate", G_TYPE_INT, (int) stream->rate, NULL);
6351 if (stream->n_channels > 0)
6352 gst_caps_set_simple (stream->caps,
6353 "channels", G_TYPE_INT, stream->n_channels, NULL);
6354 if (stream->n_channels > 2) {
6355 /* FIXME: Need to parse the 'chan' atom to get channel layouts
6356 * correctly; this is just the minimum we can do - assume
6357 * we don't actually have any channel positions. */
6358 gst_caps_set_simple (stream->caps,
6359 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
6365 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
6366 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
6367 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
6368 gst_pad_set_active (stream->pad, TRUE);
6370 gst_pad_use_fixed_caps (stream->pad);
6372 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
6373 if (stream->new_stream) {
6376 GstStreamFlags stream_flags;
6379 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
6382 if (gst_event_parse_group_id (event, &qtdemux->group_id))
6383 qtdemux->have_group_id = TRUE;
6385 qtdemux->have_group_id = FALSE;
6386 gst_event_unref (event);
6387 } else if (!qtdemux->have_group_id) {
6388 qtdemux->have_group_id = TRUE;
6389 qtdemux->group_id = gst_util_group_id_next ();
6392 stream->new_stream = FALSE;
6394 gst_pad_create_stream_id_printf (stream->pad,
6395 GST_ELEMENT_CAST (qtdemux), "%03u", stream->track_id);
6396 event = gst_event_new_stream_start (stream_id);
6397 if (qtdemux->have_group_id)
6398 gst_event_set_group_id (event, qtdemux->group_id);
6399 stream_flags = GST_STREAM_FLAG_NONE;
6400 if (stream->disabled)
6401 stream_flags |= GST_STREAM_FLAG_UNSELECT;
6403 stream_flags |= GST_STREAM_FLAG_SPARSE;
6404 gst_event_set_stream_flags (event, stream_flags);
6405 gst_pad_push_event (stream->pad, event);
6408 gst_pad_set_caps (stream->pad, stream->caps);
6409 stream->new_caps = FALSE;
6415 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
6416 QtDemuxStream * stream, GstTagList * list)
6418 /* consistent default for push based mode */
6419 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
6421 if (stream->subtype == FOURCC_vide) {
6422 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
6425 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
6428 gst_qtdemux_configure_stream (qtdemux, stream);
6429 qtdemux->n_video_streams++;
6430 } else if (stream->subtype == FOURCC_soun) {
6431 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
6434 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
6436 gst_qtdemux_configure_stream (qtdemux, stream);
6437 qtdemux->n_audio_streams++;
6438 } else if (stream->subtype == FOURCC_strm) {
6439 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
6440 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
6441 || stream->subtype == FOURCC_sbtl) {
6442 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
6445 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
6447 gst_qtdemux_configure_stream (qtdemux, stream);
6448 qtdemux->n_sub_streams++;
6449 } else if (stream->caps) {
6450 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
6453 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
6455 gst_qtdemux_configure_stream (qtdemux, stream);
6456 qtdemux->n_video_streams++;
6458 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
6463 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
6464 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
6465 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
6466 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
6468 if (stream->pending_tags)
6469 gst_tag_list_unref (stream->pending_tags);
6470 stream->pending_tags = list;
6472 /* global tags go on each pad anyway */
6473 stream->send_global_tags = TRUE;
6477 gst_tag_list_unref (list);
6481 /* find next atom with @fourcc starting at @offset */
6482 static GstFlowReturn
6483 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
6484 guint64 * length, guint32 fourcc)
6490 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
6491 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
6497 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
6498 if (G_UNLIKELY (ret != GST_FLOW_OK))
6500 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
6503 gst_buffer_unref (buf);
6506 gst_buffer_map (buf, &map, GST_MAP_READ);
6507 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
6508 gst_buffer_unmap (buf, &map);
6509 gst_buffer_unref (buf);
6511 if (G_UNLIKELY (*length == 0)) {
6512 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
6513 ret = GST_FLOW_ERROR;
6517 if (lfourcc == fourcc) {
6518 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
6522 GST_LOG_OBJECT (qtdemux,
6523 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
6524 GST_FOURCC_ARGS (fourcc), *offset);
6533 /* might simply have had last one */
6534 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
6539 /* should only do something in pull mode */
6540 /* call with OBJECT lock */
6541 static GstFlowReturn
6542 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
6544 guint64 length, offset;
6545 GstBuffer *buf = NULL;
6546 GstFlowReturn ret = GST_FLOW_OK;
6547 GstFlowReturn res = GST_FLOW_OK;
6550 offset = qtdemux->moof_offset;
6551 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
6554 GST_DEBUG_OBJECT (qtdemux, "no next moof");
6555 return GST_FLOW_EOS;
6558 /* best not do pull etc with lock held */
6559 GST_OBJECT_UNLOCK (qtdemux);
6561 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
6562 if (ret != GST_FLOW_OK)
6565 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
6566 if (G_UNLIKELY (ret != GST_FLOW_OK))
6568 gst_buffer_map (buf, &map, GST_MAP_READ);
6569 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
6570 gst_buffer_unmap (buf, &map);
6571 gst_buffer_unref (buf);
6576 gst_buffer_unmap (buf, &map);
6577 gst_buffer_unref (buf);
6581 /* look for next moof */
6582 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
6583 if (G_UNLIKELY (ret != GST_FLOW_OK))
6587 GST_OBJECT_LOCK (qtdemux);
6589 qtdemux->moof_offset = offset;
6595 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
6597 res = GST_FLOW_ERROR;
6602 /* maybe upstream temporarily flushing */
6603 if (ret != GST_FLOW_FLUSHING) {
6604 GST_DEBUG_OBJECT (qtdemux, "no next moof");
6607 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
6608 /* resume at current position next time */
6615 /* initialise bytereaders for stbl sub-atoms */
6617 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
6619 stream->stbl_index = -1; /* no samples have yet been parsed */
6620 stream->sample_index = -1;
6622 /* time-to-sample atom */
6623 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
6626 /* copy atom data into a new buffer for later use */
6627 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
6629 /* skip version + flags */
6630 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
6631 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
6633 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
6635 /* make sure there's enough data */
6636 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
6637 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
6638 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
6639 stream->n_sample_times);
6640 if (!stream->n_sample_times)
6644 /* sync sample atom */
6645 stream->stps_present = FALSE;
6646 if ((stream->stss_present =
6647 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
6648 &stream->stss) ? TRUE : FALSE) == TRUE) {
6649 /* copy atom data into a new buffer for later use */
6650 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
6652 /* skip version + flags */
6653 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
6654 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
6657 if (stream->n_sample_syncs) {
6658 /* make sure there's enough data */
6659 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
6663 /* partial sync sample atom */
6664 if ((stream->stps_present =
6665 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
6666 &stream->stps) ? TRUE : FALSE) == TRUE) {
6667 /* copy atom data into a new buffer for later use */
6668 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
6670 /* skip version + flags */
6671 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
6672 !gst_byte_reader_get_uint32_be (&stream->stps,
6673 &stream->n_sample_partial_syncs))
6676 /* if there are no entries, the stss table contains the real
6678 if (stream->n_sample_partial_syncs) {
6679 /* make sure there's enough data */
6680 if (!qt_atom_parser_has_chunks (&stream->stps,
6681 stream->n_sample_partial_syncs, 4))
6688 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
6691 /* copy atom data into a new buffer for later use */
6692 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
6694 /* skip version + flags */
6695 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
6696 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
6699 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
6702 if (!stream->n_samples)
6705 /* sample-to-chunk atom */
6706 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
6709 /* copy atom data into a new buffer for later use */
6710 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
6712 /* skip version + flags */
6713 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
6714 !gst_byte_reader_get_uint32_be (&stream->stsc,
6715 &stream->n_samples_per_chunk))
6718 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
6719 stream->n_samples_per_chunk);
6721 /* make sure there's enough data */
6722 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
6728 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
6729 stream->co_size = sizeof (guint32);
6730 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
6732 stream->co_size = sizeof (guint64);
6736 /* copy atom data into a new buffer for later use */
6737 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
6739 /* skip version + flags */
6740 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
6743 /* chunks_are_samples == TRUE means treat chunks as samples */
6744 stream->chunks_are_samples = stream->sample_size && !stream->sampled;
6745 if (stream->chunks_are_samples) {
6746 /* treat chunks as samples */
6747 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
6750 /* skip number of entries */
6751 if (!gst_byte_reader_skip (&stream->stco, 4))
6754 /* make sure there are enough data in the stsz atom */
6755 if (!stream->sample_size) {
6756 /* different sizes for each sample */
6757 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
6762 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
6763 stream->n_samples, (guint) sizeof (QtDemuxSample),
6764 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
6766 if (stream->n_samples >=
6767 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
6768 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
6769 "be larger than %uMB (broken file?)", stream->n_samples,
6770 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
6774 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
6775 if (!stream->samples) {
6776 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
6781 /* composition time-to-sample */
6782 if ((stream->ctts_present =
6783 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
6784 &stream->ctts) ? TRUE : FALSE) == TRUE) {
6785 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
6787 /* copy atom data into a new buffer for later use */
6788 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
6790 /* skip version + flags */
6791 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
6792 || !gst_byte_reader_get_uint32_be (&stream->ctts,
6793 &stream->n_composition_times))
6796 /* make sure there's enough data */
6797 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
6801 /* This is optional, if missing we iterate the ctts */
6802 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
6803 if (!gst_byte_reader_skip (&cslg, 1 + 3)
6804 || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
6805 g_free ((gpointer) cslg.data);
6809 gint32 cslg_least = 0;
6810 guint num_entries, pos;
6813 pos = gst_byte_reader_get_pos (&stream->ctts);
6814 num_entries = stream->n_composition_times;
6816 stream->cslg_shift = 0;
6818 for (i = 0; i < num_entries; i++) {
6821 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
6822 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
6824 if (offset < cslg_least)
6825 cslg_least = offset;
6829 stream->cslg_shift = ABS (cslg_least);
6831 stream->cslg_shift = 0;
6833 /* reset the reader so we can generate sample table */
6834 gst_byte_reader_set_pos (&stream->ctts, pos);
6837 /* Ensure the cslg_shift value is consistent so we can use it
6838 * unconditionnally to produce TS and Segment */
6839 stream->cslg_shift = 0;
6846 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
6847 (_("This file is corrupt and cannot be played.")), (NULL));
6852 gst_qtdemux_stbl_free (stream);
6853 if (!qtdemux->fragmented) {
6854 /* not quite good */
6855 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
6858 /* may pick up samples elsewhere */
6864 /* collect samples from the next sample to be parsed up to sample @n for @stream
6865 * by reading the info from @stbl
6867 * This code can be executed from both the streaming thread and the seeking
6868 * thread so it takes the object lock to protect itself
6871 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
6874 QtDemuxSample *samples, *first, *cur, *last;
6875 guint32 n_samples_per_chunk;
6878 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
6879 GST_FOURCC_FORMAT ", pad %s", GST_FOURCC_ARGS (stream->fourcc),
6880 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
6882 n_samples = stream->n_samples;
6885 goto out_of_samples;
6887 GST_OBJECT_LOCK (qtdemux);
6888 if (n <= stream->stbl_index)
6889 goto already_parsed;
6891 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
6893 if (!stream->stsz.data) {
6894 /* so we already parsed and passed all the moov samples;
6895 * onto fragmented ones */
6896 g_assert (qtdemux->fragmented);
6900 /* pointer to the sample table */
6901 samples = stream->samples;
6903 /* starts from -1, moves to the next sample index to parse */
6904 stream->stbl_index++;
6906 /* keep track of the first and last sample to fill */
6907 first = &samples[stream->stbl_index];
6910 if (!stream->chunks_are_samples) {
6911 /* set the sample sizes */
6912 if (stream->sample_size == 0) {
6913 /* different sizes for each sample */
6914 for (cur = first; cur <= last; cur++) {
6915 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
6916 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
6917 (guint) (cur - samples), cur->size);
6920 /* samples have the same size */
6921 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
6922 for (cur = first; cur <= last; cur++)
6923 cur->size = stream->sample_size;
6927 n_samples_per_chunk = stream->n_samples_per_chunk;
6930 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
6933 if (stream->stsc_chunk_index >= stream->last_chunk
6934 || stream->stsc_chunk_index < stream->first_chunk) {
6935 stream->first_chunk =
6936 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
6937 stream->samples_per_chunk =
6938 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
6939 gst_byte_reader_skip_unchecked (&stream->stsc, 4);
6941 /* chunk numbers are counted from 1 it seems */
6942 if (G_UNLIKELY (stream->first_chunk == 0))
6945 --stream->first_chunk;
6947 /* the last chunk of each entry is calculated by taking the first chunk
6948 * of the next entry; except if there is no next, where we fake it with
6950 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
6951 stream->last_chunk = G_MAXUINT32;
6953 stream->last_chunk =
6954 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
6955 if (G_UNLIKELY (stream->last_chunk == 0))
6958 --stream->last_chunk;
6961 GST_LOG_OBJECT (qtdemux,
6962 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
6963 stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
6965 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
6968 if (stream->last_chunk != G_MAXUINT32) {
6969 if (!qt_atom_parser_peek_sub (&stream->stco,
6970 stream->first_chunk * stream->co_size,
6971 (stream->last_chunk - stream->first_chunk) * stream->co_size,
6976 stream->co_chunk = stream->stco;
6977 if (!gst_byte_reader_skip (&stream->co_chunk,
6978 stream->first_chunk * stream->co_size))
6982 stream->stsc_chunk_index = stream->first_chunk;
6985 last_chunk = stream->last_chunk;
6987 if (stream->chunks_are_samples) {
6988 cur = &samples[stream->stsc_chunk_index];
6990 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
6993 stream->stsc_chunk_index = j;
6998 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
7001 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
7002 "%" G_GUINT64_FORMAT, j, cur->offset);
7004 if (stream->samples_per_frame * stream->bytes_per_frame) {
7006 (stream->samples_per_chunk * stream->n_channels) /
7007 stream->samples_per_frame * stream->bytes_per_frame;
7009 cur->size = stream->samples_per_chunk;
7012 GST_DEBUG_OBJECT (qtdemux,
7013 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
7014 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
7015 stream->stco_sample_index)), cur->size);
7017 cur->timestamp = stream->stco_sample_index;
7018 cur->duration = stream->samples_per_chunk;
7019 cur->keyframe = TRUE;
7022 stream->stco_sample_index += stream->samples_per_chunk;
7024 stream->stsc_chunk_index = j;
7026 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
7027 guint32 samples_per_chunk;
7028 guint64 chunk_offset;
7030 if (!stream->stsc_sample_index
7031 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
7032 &stream->chunk_offset))
7035 samples_per_chunk = stream->samples_per_chunk;
7036 chunk_offset = stream->chunk_offset;
7038 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
7039 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
7040 G_GUINT64_FORMAT " and size %d",
7041 (guint) (cur - samples), chunk_offset, cur->size);
7043 cur->offset = chunk_offset;
7044 chunk_offset += cur->size;
7047 if (G_UNLIKELY (cur > last)) {
7049 stream->stsc_sample_index = k + 1;
7050 stream->chunk_offset = chunk_offset;
7051 stream->stsc_chunk_index = j;
7055 stream->stsc_sample_index = 0;
7057 stream->stsc_chunk_index = j;
7059 stream->stsc_index++;
7062 if (stream->chunks_are_samples)
7066 guint32 n_sample_times;
7068 n_sample_times = stream->n_sample_times;
7071 for (i = stream->stts_index; i < n_sample_times; i++) {
7072 guint32 stts_samples;
7073 gint32 stts_duration;
7076 if (stream->stts_sample_index >= stream->stts_samples
7077 || !stream->stts_sample_index) {
7079 stream->stts_samples =
7080 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
7081 stream->stts_duration =
7082 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
7084 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
7085 i, stream->stts_samples, stream->stts_duration);
7087 stream->stts_sample_index = 0;
7090 stts_samples = stream->stts_samples;
7091 stts_duration = stream->stts_duration;
7092 stts_time = stream->stts_time;
7094 for (j = stream->stts_sample_index; j < stts_samples; j++) {
7095 GST_DEBUG_OBJECT (qtdemux,
7096 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
7097 (guint) (cur - samples), j,
7098 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
7100 cur->timestamp = stts_time;
7101 cur->duration = stts_duration;
7103 /* avoid 32-bit wrap-around,
7104 * but still mind possible 'negative' duration */
7105 stts_time += (gint64) stts_duration;
7108 if (G_UNLIKELY (cur > last)) {
7110 stream->stts_time = stts_time;
7111 stream->stts_sample_index = j + 1;
7115 stream->stts_sample_index = 0;
7116 stream->stts_time = stts_time;
7117 stream->stts_index++;
7119 /* fill up empty timestamps with the last timestamp, this can happen when
7120 * the last samples do not decode and so we don't have timestamps for them.
7121 * We however look at the last timestamp to estimate the track length so we
7122 * need something in here. */
7123 for (; cur < last; cur++) {
7124 GST_DEBUG_OBJECT (qtdemux,
7125 "fill sample %d: timestamp %" GST_TIME_FORMAT,
7126 (guint) (cur - samples),
7127 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
7128 cur->timestamp = stream->stts_time;
7134 /* sample sync, can be NULL */
7135 if (stream->stss_present == TRUE) {
7136 guint32 n_sample_syncs;
7138 n_sample_syncs = stream->n_sample_syncs;
7140 if (!n_sample_syncs) {
7141 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
7142 stream->all_keyframe = TRUE;
7144 for (i = stream->stss_index; i < n_sample_syncs; i++) {
7145 /* note that the first sample is index 1, not 0 */
7148 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
7150 if (G_LIKELY (index > 0 && index <= n_samples)) {
7152 samples[index].keyframe = TRUE;
7153 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
7154 /* and exit if we have enough samples */
7155 if (G_UNLIKELY (index >= n)) {
7162 stream->stss_index = i;
7165 /* stps marks partial sync frames like open GOP I-Frames */
7166 if (stream->stps_present == TRUE) {
7167 guint32 n_sample_partial_syncs;
7169 n_sample_partial_syncs = stream->n_sample_partial_syncs;
7171 /* if there are no entries, the stss table contains the real
7173 if (n_sample_partial_syncs) {
7174 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
7175 /* note that the first sample is index 1, not 0 */
7178 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
7180 if (G_LIKELY (index > 0 && index <= n_samples)) {
7182 samples[index].keyframe = TRUE;
7183 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
7184 /* and exit if we have enough samples */
7185 if (G_UNLIKELY (index >= n)) {
7192 stream->stps_index = i;
7196 /* no stss, all samples are keyframes */
7197 stream->all_keyframe = TRUE;
7198 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
7203 /* composition time to sample */
7204 if (stream->ctts_present == TRUE) {
7205 guint32 n_composition_times;
7207 gint32 ctts_soffset;
7209 /* Fill in the pts_offsets */
7211 n_composition_times = stream->n_composition_times;
7213 for (i = stream->ctts_index; i < n_composition_times; i++) {
7214 if (stream->ctts_sample_index >= stream->ctts_count
7215 || !stream->ctts_sample_index) {
7216 stream->ctts_count =
7217 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
7218 stream->ctts_soffset =
7219 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
7220 stream->ctts_sample_index = 0;
7223 ctts_count = stream->ctts_count;
7224 ctts_soffset = stream->ctts_soffset;
7226 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
7227 cur->pts_offset = ctts_soffset;
7230 if (G_UNLIKELY (cur > last)) {
7232 stream->ctts_sample_index = j + 1;
7236 stream->ctts_sample_index = 0;
7237 stream->ctts_index++;
7241 stream->stbl_index = n;
7242 /* if index has been completely parsed, free data that is no-longer needed */
7243 if (n + 1 == stream->n_samples) {
7244 gst_qtdemux_stbl_free (stream);
7245 GST_DEBUG_OBJECT (qtdemux,
7246 "parsed all available samples; checking for more");
7247 while (n + 1 == stream->n_samples)
7248 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
7251 GST_OBJECT_UNLOCK (qtdemux);
7258 GST_LOG_OBJECT (qtdemux,
7259 "Tried to parse up to sample %u but this sample has already been parsed",
7261 /* if fragmented, there may be more */
7262 if (qtdemux->fragmented && n == stream->stbl_index)
7264 GST_OBJECT_UNLOCK (qtdemux);
7270 GST_LOG_OBJECT (qtdemux,
7271 "Tried to parse up to sample %u but there are only %u samples", n + 1,
7273 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7274 (_("This file is corrupt and cannot be played.")), (NULL));
7279 GST_OBJECT_UNLOCK (qtdemux);
7280 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7281 (_("This file is corrupt and cannot be played.")), (NULL));
7286 /* collect all segment info for @stream.
7289 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
7294 /* parse and prepare segment info from the edit list */
7295 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
7296 stream->n_segments = 0;
7297 stream->segments = NULL;
7298 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
7306 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
7307 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
7310 buffer = elst->data;
7312 n_segments = QT_UINT32 (buffer + 12);
7314 /* we might allocate a bit too much, at least allocate 1 segment */
7315 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
7317 /* segments always start from 0 */
7321 for (i = 0; i < n_segments; i++) {
7324 QtDemuxSegment *segment;
7327 media_time = QT_UINT32 (buffer + 20 + i * 12);
7328 duration = QT_UINT32 (buffer + 16 + i * 12);
7330 segment = &stream->segments[count++];
7332 /* time and duration expressed in global timescale */
7333 segment->time = stime;
7334 /* add non scaled values so we don't cause roundoff errors */
7336 stime = QTTIME_TO_GSTTIME (qtdemux, time);
7337 segment->stop_time = stime;
7338 segment->duration = stime - segment->time;
7340 segment->trak_media_start = media_time;
7341 /* media_time expressed in stream timescale */
7342 if (media_time != G_MAXUINT32) {
7343 segment->media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
7344 segment->media_stop = segment->media_start + segment->duration;
7346 segment->media_start = GST_CLOCK_TIME_NONE;
7347 segment->media_stop = GST_CLOCK_TIME_NONE;
7349 rate_int = GST_READ_UINT32_BE (buffer + 24 + i * 12);
7351 if (rate_int <= 1) {
7352 /* 0 is not allowed, some programs write 1 instead of the floating point
7354 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
7358 segment->rate = rate_int / 65536.0;
7361 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
7362 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
7363 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
7364 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
7365 i, GST_TIME_ARGS (segment->time),
7366 GST_TIME_ARGS (segment->duration),
7367 GST_TIME_ARGS (segment->media_start), media_time,
7368 GST_TIME_ARGS (segment->media_stop),
7369 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
7371 if (segment->stop_time > qtdemux->segment.stop) {
7372 GST_WARNING_OBJECT (qtdemux, "Segment %d "
7373 " extends to %" GST_TIME_FORMAT
7374 " past the end of the file duration %" GST_TIME_FORMAT
7375 " it will be truncated", i, GST_TIME_ARGS (segment->stop_time),
7376 GST_TIME_ARGS (qtdemux->segment.stop));
7377 qtdemux->segment.stop = segment->stop_time;
7380 GST_DEBUG_OBJECT (qtdemux, "found %d segments", count);
7381 stream->n_segments = count;
7385 /* push based does not handle segments, so act accordingly here,
7386 * and warn if applicable */
7387 if (!qtdemux->pullbased) {
7388 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
7389 /* remove and use default one below, we stream like it anyway */
7390 g_free (stream->segments);
7391 stream->segments = NULL;
7392 stream->n_segments = 0;
7395 /* no segments, create one to play the complete trak */
7396 if (stream->n_segments == 0) {
7397 GstClockTime stream_duration =
7398 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
7400 if (stream->segments == NULL)
7401 stream->segments = g_new (QtDemuxSegment, 1);
7403 /* represent unknown our way */
7404 if (stream_duration == 0)
7405 stream_duration = GST_CLOCK_TIME_NONE;
7407 stream->segments[0].time = 0;
7408 stream->segments[0].stop_time = stream_duration;
7409 stream->segments[0].duration = stream_duration;
7410 stream->segments[0].media_start = 0;
7411 stream->segments[0].media_stop = stream_duration;
7412 stream->segments[0].rate = 1.0;
7413 stream->segments[0].trak_media_start = 0;
7415 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
7416 GST_TIME_ARGS (stream_duration));
7417 stream->n_segments = 1;
7418 stream->dummy_segment = TRUE;
7420 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
7426 * Parses the stsd atom of a svq3 trak looking for
7427 * the SMI and gama atoms.
7430 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
7431 guint8 ** gamma, GstBuffer ** seqh)
7433 guint8 *_gamma = NULL;
7434 GstBuffer *_seqh = NULL;
7435 guint8 *stsd_data = stsd->data;
7436 guint32 length = QT_UINT32 (stsd_data);
7440 GST_WARNING_OBJECT (qtdemux, "stsd too short");
7446 version = QT_UINT16 (stsd_data);
7451 while (length > 8) {
7452 guint32 fourcc, size;
7454 size = QT_UINT32 (stsd_data);
7455 fourcc = QT_FOURCC (stsd_data + 4);
7456 data = stsd_data + 8;
7459 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
7460 "svq3 atom parsing");
7469 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
7470 " for gama atom, expected 12", size);
7475 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
7477 if (_seqh != NULL) {
7478 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
7479 " found, ignoring");
7481 seqh_size = QT_UINT32 (data + 4);
7482 if (seqh_size > 0) {
7483 _seqh = gst_buffer_new_and_alloc (seqh_size);
7484 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
7491 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
7492 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
7496 if (size <= length) {
7502 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
7505 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
7506 G_GUINT16_FORMAT, version);
7517 gst_buffer_unref (_seqh);
7522 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
7529 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
7530 * atom that might contain a 'data' atom with the rtsp uri.
7531 * This case was reported in bug #597497, some info about
7532 * the hndl atom can be found in TN1195
7534 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
7535 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
7538 guint32 dref_num_entries = 0;
7539 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
7540 gst_byte_reader_skip (&dref, 4) &&
7541 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
7544 /* search dref entries for hndl atom */
7545 for (i = 0; i < dref_num_entries; i++) {
7546 guint32 size = 0, type;
7547 guint8 string_len = 0;
7548 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
7549 qt_atom_parser_get_fourcc (&dref, &type)) {
7550 if (type == FOURCC_hndl) {
7551 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
7553 /* skip data reference handle bytes and the
7554 * following pascal string and some extra 4
7555 * bytes I have no idea what are */
7556 if (!gst_byte_reader_skip (&dref, 4) ||
7557 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
7558 !gst_byte_reader_skip (&dref, string_len + 4)) {
7559 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
7563 /* iterate over the atoms to find the data atom */
7564 while (gst_byte_reader_get_remaining (&dref) >= 8) {
7568 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
7569 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
7570 if (atom_type == FOURCC_data) {
7571 const guint8 *uri_aux = NULL;
7573 /* found the data atom that might contain the rtsp uri */
7574 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
7575 "hndl atom, interpreting it as an URI");
7576 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
7578 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
7579 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
7581 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
7582 "didn't contain a rtsp address");
7584 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
7589 /* skipping to the next entry */
7590 if (!gst_byte_reader_skip (&dref, atom_size - 8))
7593 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
7600 /* skip to the next entry */
7601 if (!gst_byte_reader_skip (&dref, size - 8))
7604 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
7607 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
7613 #define AMR_NB_ALL_MODES 0x81ff
7614 #define AMR_WB_ALL_MODES 0x83ff
7616 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
7618 /* The 'damr' atom is of the form:
7620 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
7621 * 32 b 8 b 16 b 8 b 8 b
7623 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
7624 * represents the highest mode used in the stream (and thus the maximum
7625 * bitrate), with a couple of special cases as seen below.
7628 /* Map of frame type ID -> bitrate */
7629 static const guint nb_bitrates[] = {
7630 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
7632 static const guint wb_bitrates[] = {
7633 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
7639 gst_buffer_map (buf, &map, GST_MAP_READ);
7641 if (map.size != 0x11) {
7642 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
7646 if (QT_FOURCC (map.data + 4) != GST_MAKE_FOURCC ('d', 'a', 'm', 'r')) {
7647 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
7648 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
7652 mode_set = QT_UINT16 (map.data + 13);
7654 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
7655 max_mode = 7 + (wb ? 1 : 0);
7657 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
7658 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
7660 if (max_mode == -1) {
7661 GST_DEBUG ("No mode indication was found (mode set) = %x",
7666 gst_buffer_unmap (buf, &map);
7667 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
7670 gst_buffer_unmap (buf, &map);
7675 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
7676 GstByteReader * reader, guint32 * matrix, const gchar * atom)
7679 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
7685 if (gst_byte_reader_get_remaining (reader) < 36)
7688 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
7689 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
7690 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
7691 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
7692 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
7693 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
7694 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
7695 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
7696 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
7698 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
7699 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
7700 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
7702 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
7703 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
7705 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
7706 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
7713 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
7714 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
7721 * This macro will only compare value abdegh, it expects cfi to have already
7724 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
7725 (m)[3] == (d << 16) && (m)[4] == (e << 16))
7727 /* only handle the cases where the last column has standard values */
7728 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
7729 const gchar *rotation_tag = NULL;
7731 /* no rotation needed */
7732 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
7734 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
7735 rotation_tag = "rotate-90";
7736 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
7737 rotation_tag = "rotate-180";
7738 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
7739 rotation_tag = "rotate-270";
7741 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
7744 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
7746 if (rotation_tag != NULL) {
7747 if (*taglist == NULL)
7748 *taglist = gst_tag_list_new_empty ();
7749 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
7750 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
7753 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
7758 * With each track we associate a new QtDemuxStream that contains all the info
7760 * traks that do not decode to something (like strm traks) will not have a pad.
7763 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
7782 QtDemuxStream *stream = NULL;
7783 gboolean new_stream = FALSE;
7784 gchar *codec = NULL;
7785 const guint8 *stsd_data;
7786 guint16 lang_code; /* quicktime lang code or packed iso code */
7788 guint32 tkhd_flags = 0;
7789 guint8 tkhd_version = 0;
7791 guint value_size, stsd_len, len;
7794 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
7796 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
7797 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
7798 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
7801 /* pick between 64 or 32 bits */
7802 value_size = tkhd_version == 1 ? 8 : 4;
7803 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
7804 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
7807 if (!qtdemux->got_moov) {
7808 if (qtdemux_find_stream (qtdemux, track_id))
7809 goto existing_stream;
7810 stream = _create_stream ();
7811 stream->track_id = track_id;
7814 stream = qtdemux_find_stream (qtdemux, track_id);
7816 GST_WARNING_OBJECT (qtdemux, "Stream not found, going to ignore it");
7821 if (stream->pending_tags == NULL)
7822 stream->pending_tags = gst_tag_list_new_empty ();
7824 if ((tkhd_flags & 1) == 0)
7825 stream->disabled = TRUE;
7827 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
7828 tkhd_version, tkhd_flags, stream->track_id);
7830 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
7833 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
7834 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
7835 if (qtdemux->major_brand != FOURCC_mjp2 ||
7836 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
7840 len = QT_UINT32 ((guint8 *) mdhd->data);
7841 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
7842 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
7843 if (version == 0x01000000) {
7846 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
7847 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
7848 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
7852 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
7853 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
7854 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
7857 if (lang_code < 0x400) {
7858 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
7859 } else if (lang_code == 0x7fff) {
7860 stream->lang_id[0] = 0; /* unspecified */
7862 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
7863 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
7864 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
7865 stream->lang_id[3] = 0;
7868 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
7870 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
7872 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
7873 lang_code, stream->lang_id);
7875 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
7878 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
7879 /* chapters track reference */
7880 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
7882 gsize length = GST_READ_UINT32_BE (chap->data);
7883 if (qtdemux->chapters_track_id)
7884 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
7887 qtdemux->chapters_track_id =
7888 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
7893 /* fragmented files may have bogus duration in moov */
7894 if (!qtdemux->fragmented &&
7895 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
7896 guint64 tdur1, tdur2;
7898 /* don't overflow */
7899 tdur1 = stream->timescale * (guint64) qtdemux->duration;
7900 tdur2 = qtdemux->timescale * (guint64) stream->duration;
7903 * some of those trailers, nowadays, have prologue images that are
7904 * themselves vide tracks as well. I haven't really found a way to
7905 * identify those yet, except for just looking at their duration. */
7906 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
7907 GST_WARNING_OBJECT (qtdemux,
7908 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
7909 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
7910 "found, assuming preview image or something; skipping track",
7911 stream->duration, stream->timescale, qtdemux->duration,
7912 qtdemux->timescale);
7918 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
7921 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
7922 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
7924 len = QT_UINT32 ((guint8 *) hdlr->data);
7926 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
7927 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
7928 GST_FOURCC_ARGS (stream->subtype));
7930 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
7933 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
7936 /*parse svmi header if existing */
7937 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
7939 len = QT_UINT32 ((guint8 *) svmi->data);
7940 version = QT_UINT32 ((guint8 *) svmi->data + 8);
7942 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
7943 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
7944 guint8 frame_type, frame_layout;
7946 /* MPEG-A stereo video */
7947 if (qtdemux->major_brand == FOURCC_ss02)
7948 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
7950 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
7951 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
7952 switch (frame_type) {
7954 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
7957 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
7960 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
7963 /* mode 3 is primary/secondary view sequence, ie
7964 * left/right views in separate tracks. See section 7.2
7965 * of ISO/IEC 23000-11:2009 */
7966 GST_FIXME_OBJECT (qtdemux,
7967 "Implement stereo video in separate streams");
7970 if ((frame_layout & 0x1) == 0)
7971 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
7973 GST_LOG_OBJECT (qtdemux,
7974 "StereoVideo: composition type: %u, is_left_first: %u",
7975 frame_type, frame_layout);
7976 stream->multiview_mode = mode;
7977 stream->multiview_flags = flags;
7982 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
7984 stsd_data = (const guint8 *) stsd->data;
7986 /* stsd should at least have one entry */
7987 stsd_len = QT_UINT32 (stsd_data);
7988 if (stsd_len < 24) {
7989 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
7990 if (stream->subtype == FOURCC_vivo) {
7998 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
8000 /* and that entry should fit within stsd */
8001 len = QT_UINT32 (stsd_data + 16);
8002 if (len > stsd_len + 16)
8005 stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
8006 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
8007 GST_FOURCC_ARGS (stream->fourcc));
8008 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
8010 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi) ||
8011 ((fourcc & 0x00FFFFFF) == GST_MAKE_FOURCC ('e', 'n', 'c', 0)))
8012 goto error_encrypted;
8014 if (stream->subtype == FOURCC_vide) {
8015 guint32 w = 0, h = 0;
8017 gint depth, palette_size, palette_count;
8019 guint32 *palette_data = NULL;
8021 stream->sampled = TRUE;
8023 /* version 1 uses some 64-bit ints */
8024 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
8027 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
8030 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
8031 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
8034 stream->display_width = w >> 16;
8035 stream->display_height = h >> 16;
8037 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
8038 &stream->pending_tags);
8044 stream->width = QT_UINT16 (stsd_data + offset + 32);
8045 stream->height = QT_UINT16 (stsd_data + offset + 34);
8046 stream->fps_n = 0; /* this is filled in later */
8047 stream->fps_d = 0; /* this is filled in later */
8048 stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
8049 stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
8051 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
8052 stream->width, stream->height, stream->bits_per_sample,
8053 stream->color_table_id);
8055 depth = stream->bits_per_sample;
8057 /* more than 32 bits means grayscale */
8058 gray = (depth > 32);
8059 /* low 32 bits specify the depth */
8062 /* different number of palette entries is determined by depth. */
8064 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
8065 palette_count = (1 << depth);
8066 palette_size = palette_count * 4;
8068 if (stream->color_table_id) {
8069 switch (palette_count) {
8073 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
8076 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
8080 palette_data = g_memdup (ff_qt_grayscale_palette_16, palette_size);
8082 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
8086 palette_data = g_memdup (ff_qt_grayscale_palette_256, palette_size);
8088 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
8091 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
8092 (_("The video in this file might not play correctly.")),
8093 ("unsupported palette depth %d", depth));
8097 gint i, j, start, end;
8103 start = QT_UINT32 (stsd_data + offset + 86);
8104 palette_count = QT_UINT16 (stsd_data + offset + 90);
8105 end = QT_UINT16 (stsd_data + offset + 92);
8107 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
8108 start, end, palette_count);
8115 if (len < 94 + (end - start) * 8)
8118 /* palette is always the same size */
8119 palette_data = g_malloc0 (256 * 4);
8120 palette_size = 256 * 4;
8122 for (j = 0, i = start; i <= end; j++, i++) {
8125 a = QT_UINT16 (stsd_data + offset + 94 + (j * 8));
8126 r = QT_UINT16 (stsd_data + offset + 96 + (j * 8));
8127 g = QT_UINT16 (stsd_data + offset + 98 + (j * 8));
8128 b = QT_UINT16 (stsd_data + offset + 100 + (j * 8));
8130 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
8131 (g & 0xff00) | (b >> 8);
8136 qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
8137 if (G_UNLIKELY (!stream->caps)) {
8138 g_free (palette_data);
8139 goto unknown_stream;
8143 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
8144 GST_TAG_VIDEO_CODEC, codec, NULL);
8153 if (stream->rgb8_palette)
8154 gst_memory_unref (stream->rgb8_palette);
8155 stream->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
8156 palette_data, palette_size, 0, palette_size, palette_data, g_free);
8158 s = gst_caps_get_structure (stream->caps, 0);
8160 /* non-raw video has a palette_data property. raw video has the palette as
8161 * an extra plane that we append to the output buffers before we push
8163 if (!gst_structure_has_name (s, "video/x-raw")) {
8166 palette = gst_buffer_new ();
8167 gst_buffer_append_memory (palette, stream->rgb8_palette);
8168 stream->rgb8_palette = NULL;
8170 gst_caps_set_simple (stream->caps, "palette_data",
8171 GST_TYPE_BUFFER, palette, NULL);
8172 gst_buffer_unref (palette);
8174 } else if (palette_count != 0) {
8175 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
8176 (NULL), ("Unsupported palette depth %d", depth));
8179 GST_LOG_OBJECT (qtdemux, "frame count: %u",
8180 QT_UINT16 (stsd_data + offset + 48));
8184 /* pick 'the' stsd child */
8185 mp4v = qtdemux_tree_get_child_by_type (stsd, fourcc);
8187 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
8188 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
8192 const guint8 *pasp_data = (const guint8 *) pasp->data;
8194 stream->par_w = QT_UINT32 (pasp_data + 8);
8195 stream->par_h = QT_UINT32 (pasp_data + 12);
8202 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
8209 gint len = QT_UINT32 (stsd_data) - 0x66;
8210 const guint8 *avc_data = stsd_data + 0x66;
8213 while (len >= 0x8) {
8216 if (QT_UINT32 (avc_data) <= len)
8217 size = QT_UINT32 (avc_data) - 0x8;
8222 /* No real data, so break out */
8225 switch (QT_FOURCC (avc_data + 0x4)) {
8228 /* parse, if found */
8231 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
8233 /* First 4 bytes are the length of the atom, the next 4 bytes
8234 * are the fourcc, the next 1 byte is the version, and the
8235 * subsequent bytes are profile_tier_level structure like data. */
8236 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
8237 avc_data + 8 + 1, size - 1);
8238 buf = gst_buffer_new_and_alloc (size);
8239 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
8240 gst_caps_set_simple (stream->caps,
8241 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8242 gst_buffer_unref (buf);
8250 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
8252 /* First 4 bytes are the length of the atom, the next 4 bytes
8253 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
8254 * next 1 byte is the version, and the
8255 * subsequent bytes are sequence parameter set like data. */
8257 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
8259 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
8260 avc_data + 8 + 40 + 1, size - 1);
8262 buf = gst_buffer_new_and_alloc (size);
8263 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
8264 gst_caps_set_simple (stream->caps,
8265 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8266 gst_buffer_unref (buf);
8272 guint avg_bitrate, max_bitrate;
8274 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
8278 max_bitrate = QT_UINT32 (avc_data + 0xc);
8279 avg_bitrate = QT_UINT32 (avc_data + 0x10);
8281 if (!max_bitrate && !avg_bitrate)
8284 /* Some muxers seem to swap the average and maximum bitrates
8285 * (I'm looking at you, YouTube), so we swap for sanity. */
8286 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
8287 guint temp = avg_bitrate;
8289 avg_bitrate = max_bitrate;
8293 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
8294 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
8295 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
8297 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
8298 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
8299 GST_TAG_BITRATE, avg_bitrate, NULL);
8310 avc_data += size + 8;
8319 gint len = QT_UINT32 (stsd_data) - 0x66;
8320 const guint8 *hevc_data = stsd_data + 0x66;
8323 while (len >= 0x8) {
8326 if (QT_UINT32 (hevc_data) <= len)
8327 size = QT_UINT32 (hevc_data) - 0x8;
8332 /* No real data, so break out */
8335 switch (QT_FOURCC (hevc_data + 0x4)) {
8338 /* parse, if found */
8341 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
8343 /* First 4 bytes are the length of the atom, the next 4 bytes
8344 * are the fourcc, the next 1 byte is the version, and the
8345 * subsequent bytes are sequence parameter set like data. */
8346 gst_codec_utils_h265_caps_set_level_tier_and_profile
8347 (stream->caps, hevc_data + 8 + 1, size - 1);
8349 buf = gst_buffer_new_and_alloc (size);
8350 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
8351 gst_caps_set_simple (stream->caps,
8352 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8353 gst_buffer_unref (buf);
8360 hevc_data += size + 8;
8371 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
8372 GST_FOURCC_ARGS (fourcc));
8374 /* codec data might be in glbl extension atom */
8376 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
8382 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
8384 len = QT_UINT32 (data);
8387 buf = gst_buffer_new_and_alloc (len);
8388 gst_buffer_fill (buf, 0, data + 8, len);
8389 gst_caps_set_simple (stream->caps,
8390 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8391 gst_buffer_unref (buf);
8398 /* see annex I of the jpeg2000 spec */
8399 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
8401 const gchar *colorspace = NULL;
8403 guint32 ncomp_map = 0;
8404 gint32 *comp_map = NULL;
8405 guint32 nchan_def = 0;
8406 gint32 *chan_def = NULL;
8408 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
8409 /* some required atoms */
8410 mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
8413 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
8417 /* number of components; redundant with info in codestream, but useful
8419 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
8420 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
8422 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
8424 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
8427 GST_DEBUG_OBJECT (qtdemux, "found colr");
8428 /* extract colour space info */
8429 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
8430 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
8432 colorspace = "sRGB";
8435 colorspace = "GRAY";
8438 colorspace = "sYUV";
8446 /* colr is required, and only values 16, 17, and 18 are specified,
8447 so error if we have no colorspace */
8450 /* extract component mapping */
8451 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
8453 guint32 cmap_len = 0;
8455 cmap_len = QT_UINT32 (cmap->data);
8456 if (cmap_len >= 8) {
8457 /* normal box, subtract off header */
8459 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
8460 if (cmap_len % 4 == 0) {
8461 ncomp_map = (cmap_len / 4);
8462 comp_map = g_new0 (gint32, ncomp_map);
8463 for (i = 0; i < ncomp_map; i++) {
8466 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
8467 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
8468 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
8469 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
8474 /* extract channel definitions */
8475 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
8477 guint32 cdef_len = 0;
8479 cdef_len = QT_UINT32 (cdef->data);
8480 if (cdef_len >= 10) {
8481 /* normal box, subtract off header and len */
8483 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
8484 if (cdef_len % 6 == 0) {
8485 nchan_def = (cdef_len / 6);
8486 chan_def = g_new0 (gint32, nchan_def);
8487 for (i = 0; i < nchan_def; i++)
8489 for (i = 0; i < nchan_def; i++) {
8490 guint16 cn, typ, asoc;
8491 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
8492 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
8493 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
8494 if (cn < nchan_def) {
8497 chan_def[cn] = asoc;
8500 chan_def[cn] = 0; /* alpha */
8503 chan_def[cn] = -typ;
8511 gst_caps_set_simple (stream->caps,
8512 "num-components", G_TYPE_INT, ncomp, NULL);
8513 gst_caps_set_simple (stream->caps,
8514 "colorspace", G_TYPE_STRING, colorspace, NULL);
8517 GValue arr = { 0, };
8518 GValue elt = { 0, };
8520 g_value_init (&arr, GST_TYPE_ARRAY);
8521 g_value_init (&elt, G_TYPE_INT);
8522 for (i = 0; i < ncomp_map; i++) {
8523 g_value_set_int (&elt, comp_map[i]);
8524 gst_value_array_append_value (&arr, &elt);
8526 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
8527 "component-map", &arr);
8528 g_value_unset (&elt);
8529 g_value_unset (&arr);
8534 GValue arr = { 0, };
8535 GValue elt = { 0, };
8537 g_value_init (&arr, GST_TYPE_ARRAY);
8538 g_value_init (&elt, G_TYPE_INT);
8539 for (i = 0; i < nchan_def; i++) {
8540 g_value_set_int (&elt, chan_def[i]);
8541 gst_value_array_append_value (&arr, &elt);
8543 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
8544 "channel-definitions", &arr);
8545 g_value_unset (&elt);
8546 g_value_unset (&arr);
8550 /* some optional atoms */
8551 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
8552 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
8554 /* indicate possible fields in caps */
8556 data = (guint8 *) field->data + 8;
8558 gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
8559 (gint) * data, NULL);
8561 /* add codec_data if provided */
8566 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
8567 data = prefix->data;
8568 len = QT_UINT32 (data);
8571 buf = gst_buffer_new_and_alloc (len);
8572 gst_buffer_fill (buf, 0, data + 8, len);
8573 gst_caps_set_simple (stream->caps,
8574 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8575 gst_buffer_unref (buf);
8584 GstBuffer *seqh = NULL;
8585 guint8 *gamma_data = NULL;
8586 gint len = QT_UINT32 (stsd_data);
8588 qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
8590 gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
8591 QT_FP32 (gamma_data), NULL);
8594 /* sorry for the bad name, but we don't know what this is, other
8595 * than its own fourcc */
8596 gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
8600 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
8601 buf = gst_buffer_new_and_alloc (len);
8602 gst_buffer_fill (buf, 0, stsd_data, len);
8603 gst_caps_set_simple (stream->caps,
8604 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8605 gst_buffer_unref (buf);
8611 gst_caps_set_simple (stream->caps,
8612 "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
8619 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
8620 xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
8624 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
8628 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
8629 /* collect the headers and store them in a stream list so that we can
8630 * send them out first */
8631 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
8641 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
8642 ovc1 = qtdemux_tree_get_child_by_type (stsd, FOURCC_ovc1);
8645 ovc1_data = ovc1->data;
8646 ovc1_len = QT_UINT32 (ovc1_data);
8647 if (ovc1_len <= 198) {
8648 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
8651 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
8652 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
8653 gst_caps_set_simple (stream->caps,
8654 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8655 gst_buffer_unref (buf);
8658 case GST_MAKE_FOURCC ('v', 'c', '-', '1'):
8660 gint len = QT_UINT32 (stsd_data) - 0x66;
8661 const guint8 *vc1_data = stsd_data + 0x66;
8667 if (QT_UINT32 (vc1_data) <= len)
8668 size = QT_UINT32 (vc1_data) - 8;
8673 /* No real data, so break out */
8676 switch (QT_FOURCC (vc1_data + 0x4)) {
8677 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
8681 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
8682 buf = gst_buffer_new_and_alloc (size);
8683 gst_buffer_fill (buf, 0, vc1_data + 8, size);
8684 gst_caps_set_simple (stream->caps,
8685 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8686 gst_buffer_unref (buf);
8693 vc1_data += size + 8;
8702 GST_INFO_OBJECT (qtdemux,
8703 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
8704 GST_FOURCC_ARGS (fourcc), stream->caps);
8706 } else if (stream->subtype == FOURCC_soun) {
8707 int version, samplesize;
8708 guint16 compression_id;
8709 gboolean amrwb = FALSE;
8712 /* sample description entry (16) + sound sample description v0 (20) */
8716 version = QT_UINT32 (stsd_data + offset);
8717 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
8718 samplesize = QT_UINT16 (stsd_data + offset + 10);
8719 compression_id = QT_UINT16 (stsd_data + offset + 12);
8720 stream->rate = QT_FP32 (stsd_data + offset + 16);
8722 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
8723 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
8724 QT_UINT32 (stsd_data + offset + 4));
8725 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
8726 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
8727 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
8728 GST_LOG_OBJECT (qtdemux, "packet size: %d",
8729 QT_UINT16 (stsd_data + offset + 14));
8730 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
8732 if (compression_id == 0xfffe)
8733 stream->sampled = TRUE;
8735 /* first assume uncompressed audio */
8736 stream->bytes_per_sample = samplesize / 8;
8737 stream->samples_per_frame = stream->n_channels;
8738 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
8739 stream->samples_per_packet = stream->samples_per_frame;
8740 stream->bytes_per_packet = stream->bytes_per_sample;
8744 /* Yes, these have to be hard-coded */
8747 stream->samples_per_packet = 6;
8748 stream->bytes_per_packet = 1;
8749 stream->bytes_per_frame = 1 * stream->n_channels;
8750 stream->bytes_per_sample = 1;
8751 stream->samples_per_frame = 6 * stream->n_channels;
8756 stream->samples_per_packet = 3;
8757 stream->bytes_per_packet = 1;
8758 stream->bytes_per_frame = 1 * stream->n_channels;
8759 stream->bytes_per_sample = 1;
8760 stream->samples_per_frame = 3 * stream->n_channels;
8765 stream->samples_per_packet = 64;
8766 stream->bytes_per_packet = 34;
8767 stream->bytes_per_frame = 34 * stream->n_channels;
8768 stream->bytes_per_sample = 2;
8769 stream->samples_per_frame = 64 * stream->n_channels;
8775 stream->samples_per_packet = 1;
8776 stream->bytes_per_packet = 1;
8777 stream->bytes_per_frame = 1 * stream->n_channels;
8778 stream->bytes_per_sample = 1;
8779 stream->samples_per_frame = 1 * stream->n_channels;
8784 stream->samples_per_packet = 160;
8785 stream->bytes_per_packet = 33;
8786 stream->bytes_per_frame = 33 * stream->n_channels;
8787 stream->bytes_per_sample = 2;
8788 stream->samples_per_frame = 160 * stream->n_channels;
8795 if (version == 0x00010000) {
8796 /* sample description entry (16) + sound sample description v1 (20+16) */
8807 /* only parse extra decoding config for non-pcm audio */
8808 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
8809 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
8810 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
8811 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
8813 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
8814 stream->samples_per_packet);
8815 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
8816 stream->bytes_per_packet);
8817 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
8818 stream->bytes_per_frame);
8819 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
8820 stream->bytes_per_sample);
8822 if (!stream->sampled && stream->bytes_per_packet) {
8823 stream->samples_per_frame = (stream->bytes_per_frame /
8824 stream->bytes_per_packet) * stream->samples_per_packet;
8825 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
8826 stream->samples_per_frame);
8831 } else if (version == 0x00020000) {
8838 /* sample description entry (16) + sound sample description v2 (56) */
8842 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
8843 stream->rate = qtfp.fp;
8844 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
8846 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
8847 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
8848 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
8849 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
8850 QT_UINT32 (stsd_data + offset + 20));
8851 GST_LOG_OBJECT (qtdemux, "format flags: %X",
8852 QT_UINT32 (stsd_data + offset + 24));
8853 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
8854 QT_UINT32 (stsd_data + offset + 28));
8855 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
8856 QT_UINT32 (stsd_data + offset + 32));
8857 } else if (version != 0x00000) {
8858 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x", version);
8861 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc,
8862 stsd_data + 32, len - 16, &codec);
8870 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
8872 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
8874 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
8876 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
8879 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
8880 gst_caps_set_simple (stream->caps,
8881 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE", NULL);
8888 const guint8 *owma_data;
8889 const gchar *codec_name = NULL;
8893 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
8894 /* FIXME this should also be gst_riff_strf_auds,
8895 * but the latter one is actually missing bits-per-sample :( */
8900 gint32 nSamplesPerSec;
8901 gint32 nAvgBytesPerSec;
8903 gint16 wBitsPerSample;
8908 GST_DEBUG_OBJECT (qtdemux, "parse owma");
8909 owma = qtdemux_tree_get_child_by_type (stsd, FOURCC_owma);
8912 owma_data = owma->data;
8913 owma_len = QT_UINT32 (owma_data);
8914 if (owma_len <= 54) {
8915 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
8918 wfex = (WAVEFORMATEX *) (owma_data + 36);
8919 buf = gst_buffer_new_and_alloc (owma_len - 54);
8920 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
8921 if (wfex->wFormatTag == 0x0161) {
8922 codec_name = "Windows Media Audio";
8924 } else if (wfex->wFormatTag == 0x0162) {
8925 codec_name = "Windows Media Audio 9 Pro";
8927 } else if (wfex->wFormatTag == 0x0163) {
8928 codec_name = "Windows Media Audio 9 Lossless";
8929 /* is that correct? gstffmpegcodecmap.c is missing it, but
8930 * fluendo codec seems to support it */
8934 gst_caps_set_simple (stream->caps,
8935 "codec_data", GST_TYPE_BUFFER, buf,
8936 "wmaversion", G_TYPE_INT, version,
8937 "block_align", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->nBlockAlign),
8938 "bitrate", G_TYPE_INT, GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec),
8939 "width", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
8940 "depth", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
8942 gst_buffer_unref (buf);
8946 codec = g_strdup (codec_name);
8950 case GST_MAKE_FOURCC ('w', 'm', 'a', ' '):
8952 gint len = QT_UINT32 (stsd_data) - offset;
8953 const guint8 *wfex_data = stsd_data + offset;
8954 const gchar *codec_name = NULL;
8956 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
8957 /* FIXME this should also be gst_riff_strf_auds,
8958 * but the latter one is actually missing bits-per-sample :( */
8963 gint32 nSamplesPerSec;
8964 gint32 nAvgBytesPerSec;
8966 gint16 wBitsPerSample;
8971 /* FIXME: unify with similar wavformatex parsing code above */
8972 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
8978 if (QT_UINT32 (wfex_data) <= len)
8979 size = QT_UINT32 (wfex_data) - 8;
8984 /* No real data, so break out */
8987 switch (QT_FOURCC (wfex_data + 4)) {
8988 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
8990 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
8995 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
8996 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
8997 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
8998 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
8999 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
9000 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
9001 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
9003 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
9004 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
9005 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
9006 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
9007 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
9008 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
9010 if (wfex.wFormatTag == 0x0161) {
9011 codec_name = "Windows Media Audio";
9013 } else if (wfex.wFormatTag == 0x0162) {
9014 codec_name = "Windows Media Audio 9 Pro";
9016 } else if (wfex.wFormatTag == 0x0163) {
9017 codec_name = "Windows Media Audio 9 Lossless";
9018 /* is that correct? gstffmpegcodecmap.c is missing it, but
9019 * fluendo codec seems to support it */
9023 gst_caps_set_simple (stream->caps,
9024 "wmaversion", G_TYPE_INT, version,
9025 "block_align", G_TYPE_INT, wfex.nBlockAlign,
9026 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
9027 "width", G_TYPE_INT, wfex.wBitsPerSample,
9028 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
9030 if (size > wfex.cbSize) {
9033 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
9034 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
9035 size - wfex.cbSize);
9036 gst_caps_set_simple (stream->caps,
9037 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9038 gst_buffer_unref (buf);
9040 GST_WARNING_OBJECT (qtdemux, "no codec data");
9045 codec = g_strdup (codec_name);
9053 wfex_data += size + 8;
9065 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9066 GST_TAG_AUDIO_CODEC, codec, NULL);
9070 /* some bitrate info may have ended up in caps */
9071 s = gst_caps_get_structure (stream->caps, 0);
9072 gst_structure_get_int (s, "bitrate", &bitrate);
9074 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9075 GST_TAG_BITRATE, bitrate, NULL);
9078 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
9082 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
9084 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
9086 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
9090 /* If the fourcc's bottom 16 bits gives 'sm', then the top
9091 16 bits is a byte-swapped wave-style codec identifier,
9092 and we can find a WAVE header internally to a 'wave' atom here.
9093 This can more clearly be thought of as 'ms' as the top 16 bits, and a
9094 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
9097 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
9098 if (len < offset + 20) {
9099 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
9101 guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
9102 const guint8 *data = stsd_data + offset + 16;
9104 GNode *waveheadernode;
9106 wavenode = g_node_new ((guint8 *) data);
9107 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
9108 const guint8 *waveheader;
9111 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
9112 if (waveheadernode) {
9113 waveheader = (const guint8 *) waveheadernode->data;
9114 headerlen = QT_UINT32 (waveheader);
9116 if (headerlen > 8) {
9117 gst_riff_strf_auds *header = NULL;
9118 GstBuffer *headerbuf;
9124 headerbuf = gst_buffer_new_and_alloc (headerlen);
9125 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
9127 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
9128 headerbuf, &header, &extra)) {
9129 gst_caps_unref (stream->caps);
9130 /* FIXME: Need to do something with the channel reorder map */
9131 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
9132 header, extra, NULL, NULL, NULL);
9135 gst_buffer_unref (extra);
9140 GST_DEBUG ("Didn't find waveheadernode for this codec");
9142 g_node_destroy (wavenode);
9145 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
9149 /* FIXME: what is in the chunk? */
9152 gint len = QT_UINT32 (stsd_data);
9154 /* seems to be always = 116 = 0x74 */
9160 gint len = QT_UINT32 (stsd_data);
9163 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
9165 gst_buffer_fill (buf, 0, stsd_data + 0x4C, len - 0x4C);
9166 gst_caps_set_simple (stream->caps,
9167 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9168 gst_buffer_unref (buf);
9170 gst_caps_set_simple (stream->caps,
9171 "samplesize", G_TYPE_INT, samplesize, NULL);
9176 GNode *alac, *wave = NULL;
9178 /* apparently, m4a has this atom appended directly in the stsd entry,
9179 * while mov has it in a wave atom */
9180 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
9182 /* alac now refers to stsd entry atom */
9183 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
9185 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
9187 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
9190 const guint8 *alac_data = alac->data;
9191 gint len = QT_UINT32 (alac->data);
9195 GST_DEBUG_OBJECT (qtdemux,
9196 "discarding alac atom with unexpected len %d", len);
9198 /* codec-data contains alac atom size and prefix,
9199 * ffmpeg likes it that way, not quite gst-ish though ...*/
9200 buf = gst_buffer_new_and_alloc (len);
9201 gst_buffer_fill (buf, 0, alac->data, len);
9202 gst_caps_set_simple (stream->caps,
9203 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9204 gst_buffer_unref (buf);
9206 stream->bytes_per_frame = QT_UINT32 (alac_data + 12);
9207 stream->n_channels = QT_UINT8 (alac_data + 21);
9208 stream->rate = QT_UINT32 (alac_data + 32);
9211 gst_caps_set_simple (stream->caps,
9212 "samplesize", G_TYPE_INT, samplesize, NULL);
9220 gint len = QT_UINT32 (stsd_data);
9223 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
9226 gst_buffer_fill (buf, 0, stsd_data + 0x34, len - 0x34);
9228 /* If we have enough data, let's try to get the 'damr' atom. See
9229 * the 3GPP container spec (26.244) for more details. */
9230 if ((len - 0x34) > 8 &&
9231 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
9232 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9233 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
9236 gst_caps_set_simple (stream->caps,
9237 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9238 gst_buffer_unref (buf);
9244 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
9245 gint len = QT_UINT32 (stsd_data);
9248 guint16 sound_version = QT_UINT16 (stsd_data + 32);
9250 if (sound_version == 1) {
9251 guint16 channels = QT_UINT16 (stsd_data + 40);
9252 guint32 time_scale = QT_UINT32 (stsd_data + 46);
9253 guint8 codec_data[2];
9255 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
9257 gint sample_rate_index =
9258 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
9260 /* build AAC codec data */
9261 codec_data[0] = profile << 3;
9262 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
9263 codec_data[1] = (sample_rate_index & 0x01) << 7;
9264 codec_data[1] |= (channels & 0xF) << 3;
9266 buf = gst_buffer_new_and_alloc (2);
9267 gst_buffer_fill (buf, 0, codec_data, 2);
9268 gst_caps_set_simple (stream->caps,
9269 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9270 gst_buffer_unref (buf);
9276 GST_INFO_OBJECT (qtdemux,
9277 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
9281 GST_INFO_OBJECT (qtdemux,
9282 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
9283 GST_FOURCC_ARGS (fourcc), stream->caps);
9285 } else if (stream->subtype == FOURCC_strm) {
9286 if (fourcc == FOURCC_rtsp) {
9287 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
9289 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
9290 GST_FOURCC_ARGS (fourcc));
9291 goto unknown_stream;
9293 stream->sampled = TRUE;
9294 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
9295 || stream->subtype == FOURCC_sbtl) {
9297 stream->sampled = TRUE;
9298 stream->sparse = TRUE;
9301 qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
9303 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9304 GST_TAG_SUBTITLE_CODEC, codec, NULL);
9309 /* hunt for sort-of codec data */
9316 /* look for palette in a stsd->mp4s->esds sub-atom */
9317 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
9319 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
9322 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
9326 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
9330 GST_INFO_OBJECT (qtdemux,
9331 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
9334 GST_INFO_OBJECT (qtdemux,
9335 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
9336 GST_FOURCC_ARGS (fourcc), stream->caps);
9338 /* everything in 1 sample */
9339 stream->sampled = TRUE;
9342 qtdemux_generic_caps (qtdemux, stream, fourcc, stsd_data, &codec);
9344 if (stream->caps == NULL)
9345 goto unknown_stream;
9348 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9349 GST_TAG_SUBTITLE_CODEC, codec, NULL);
9355 /* promote to sampled format */
9356 if (stream->fourcc == FOURCC_samr) {
9357 /* force mono 8000 Hz for AMR */
9358 stream->sampled = TRUE;
9359 stream->n_channels = 1;
9360 stream->rate = 8000;
9361 } else if (stream->fourcc == FOURCC_sawb) {
9362 /* force mono 16000 Hz for AMR-WB */
9363 stream->sampled = TRUE;
9364 stream->n_channels = 1;
9365 stream->rate = 16000;
9366 } else if (stream->fourcc == FOURCC_mp4a) {
9367 stream->sampled = TRUE;
9370 /* collect sample information */
9371 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
9372 goto samples_failed;
9374 if (qtdemux->fragmented) {
9378 /* need all moov samples as basis; probably not many if any at all */
9379 /* prevent moof parsing taking of at this time */
9380 offset = qtdemux->moof_offset;
9381 qtdemux->moof_offset = 0;
9382 if (stream->n_samples &&
9383 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
9384 qtdemux->moof_offset = offset;
9385 goto samples_failed;
9387 qtdemux->moof_offset = 0;
9388 /* movie duration more reliable in this case (e.g. mehd) */
9389 if (qtdemux->segment.duration &&
9390 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
9392 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
9393 /* need defaults for fragments */
9394 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
9397 /* configure segments */
9398 if (!qtdemux_parse_segments (qtdemux, stream, trak))
9399 goto segments_failed;
9401 /* add some language tag, if useful */
9402 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
9403 strcmp (stream->lang_id, "und")) {
9404 const gchar *lang_code;
9406 /* convert ISO 639-2 code to ISO 639-1 */
9407 lang_code = gst_tag_get_language_code (stream->lang_id);
9408 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9409 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
9412 /* Check for UDTA tags */
9413 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
9414 qtdemux_parse_udta (qtdemux, stream->pending_tags, udta);
9417 /* now we are ready to add the stream */
9418 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
9419 goto too_many_streams;
9421 if (!qtdemux->got_moov) {
9422 qtdemux->streams[qtdemux->n_streams] = stream;
9423 qtdemux->n_streams++;
9424 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
9432 GST_INFO_OBJECT (qtdemux, "skip disabled track");
9434 gst_qtdemux_stream_free (qtdemux, stream);
9439 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9440 (_("This file is corrupt and cannot be played.")), (NULL));
9442 gst_qtdemux_stream_free (qtdemux, stream);
9447 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
9449 gst_qtdemux_stream_free (qtdemux, stream);
9455 /* we posted an error already */
9456 /* free stbl sub-atoms */
9457 gst_qtdemux_stbl_free (stream);
9459 gst_qtdemux_stream_free (qtdemux, stream);
9464 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
9467 gst_qtdemux_stream_free (qtdemux, stream);
9472 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
9473 GST_FOURCC_ARGS (stream->subtype));
9475 gst_qtdemux_stream_free (qtdemux, stream);
9480 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
9481 (_("This file contains too many streams. Only playing first %d"),
9482 GST_QTDEMUX_MAX_STREAMS), (NULL));
9487 /* If we can estimate the overall bitrate, and don't have information about the
9488 * stream bitrate for exactly one stream, this guesses the stream bitrate as
9489 * the overall bitrate minus the sum of the bitrates of all other streams. This
9490 * should be useful for the common case where we have one audio and one video
9491 * stream and can estimate the bitrate of one, but not the other. */
9493 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
9495 QtDemuxStream *stream = NULL;
9496 gint64 size, sys_bitrate, sum_bitrate = 0;
9497 GstClockTime duration;
9501 if (qtdemux->fragmented)
9504 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
9506 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
9508 GST_DEBUG_OBJECT (qtdemux,
9509 "Size in bytes of the stream not known - bailing");
9513 /* Subtract the header size */
9514 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
9515 size, qtdemux->header_size);
9517 if (size < qtdemux->header_size)
9520 size = size - qtdemux->header_size;
9522 if (!gst_qtdemux_get_duration (qtdemux, &duration) ||
9523 duration == GST_CLOCK_TIME_NONE) {
9524 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
9528 for (i = 0; i < qtdemux->n_streams; i++) {
9529 switch (qtdemux->streams[i]->subtype) {
9532 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
9533 qtdemux->streams[i]->caps);
9534 /* retrieve bitrate, prefer avg then max */
9536 if (qtdemux->streams[i]->pending_tags) {
9537 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
9538 GST_TAG_MAXIMUM_BITRATE, &bitrate);
9539 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
9540 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
9541 GST_TAG_NOMINAL_BITRATE, &bitrate);
9542 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
9543 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
9544 GST_TAG_BITRATE, &bitrate);
9545 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
9548 sum_bitrate += bitrate;
9551 GST_DEBUG_OBJECT (qtdemux,
9552 ">1 stream with unknown bitrate - bailing");
9555 stream = qtdemux->streams[i];
9559 /* For other subtypes, we assume no significant impact on bitrate */
9565 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
9569 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
9571 if (sys_bitrate < sum_bitrate) {
9572 /* This can happen, since sum_bitrate might be derived from maximum
9573 * bitrates and not average bitrates */
9574 GST_DEBUG_OBJECT (qtdemux,
9575 "System bitrate less than sum bitrate - bailing");
9579 bitrate = sys_bitrate - sum_bitrate;
9580 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
9581 ", Stream bitrate = %u", sys_bitrate, bitrate);
9583 if (!stream->pending_tags)
9584 stream->pending_tags = gst_tag_list_new_empty ();
9586 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9587 GST_TAG_BITRATE, bitrate, NULL);
9590 static GstFlowReturn
9591 qtdemux_prepare_streams (GstQTDemux * qtdemux)
9594 GstFlowReturn ret = GST_FLOW_OK;
9596 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
9598 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
9599 QtDemuxStream *stream = qtdemux->streams[i];
9600 guint32 sample_num = 0;
9602 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
9603 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
9605 if (qtdemux->fragmented) {
9606 /* need all moov samples first */
9607 GST_OBJECT_LOCK (qtdemux);
9608 while (stream->n_samples == 0)
9609 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
9611 GST_OBJECT_UNLOCK (qtdemux);
9613 /* discard any stray moof */
9614 qtdemux->moof_offset = 0;
9617 /* prepare braking */
9618 if (ret != GST_FLOW_ERROR)
9621 /* in pull mode, we should have parsed some sample info by now;
9622 * and quite some code will not handle no samples.
9623 * in push mode, we'll just have to deal with it */
9624 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
9625 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
9626 gst_qtdemux_remove_stream (qtdemux, i);
9631 /* parse the initial sample for use in setting the frame rate cap */
9632 while (sample_num == 0 && sample_num < stream->n_samples) {
9633 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
9637 if (stream->n_samples > 0 && stream->stbl_index >= 0) {
9638 stream->first_duration = stream->samples[0].duration;
9639 GST_LOG_OBJECT (qtdemux, "stream %d first duration %u",
9640 stream->track_id, stream->first_duration);
9647 static GstFlowReturn
9648 qtdemux_expose_streams (GstQTDemux * qtdemux)
9651 GstFlowReturn ret = GST_FLOW_OK;
9652 GSList *oldpads = NULL;
9655 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
9657 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
9658 QtDemuxStream *stream = qtdemux->streams[i];
9659 GstPad *oldpad = stream->pad;
9662 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
9663 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
9665 if ((stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl) &&
9666 stream->track_id == qtdemux->chapters_track_id) {
9667 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
9668 so that it doesn't look like a subtitle track */
9669 gst_qtdemux_remove_stream (qtdemux, i);
9674 /* now we have all info and can expose */
9675 list = stream->pending_tags;
9676 stream->pending_tags = NULL;
9678 oldpads = g_slist_prepend (oldpads, oldpad);
9679 gst_qtdemux_add_stream (qtdemux, stream, list);
9682 gst_qtdemux_guess_bitrate (qtdemux);
9684 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
9686 for (iter = oldpads; iter; iter = g_slist_next (iter)) {
9687 GstPad *oldpad = iter->data;
9689 gst_pad_push_event (oldpad, gst_event_new_eos ());
9690 gst_pad_set_active (oldpad, FALSE);
9691 gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
9692 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, oldpad);
9693 gst_object_unref (oldpad);
9696 /* check if we should post a redirect in case there is a single trak
9697 * and it is a redirecting trak */
9698 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
9701 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
9702 "an external content");
9703 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
9704 gst_structure_new ("redirect",
9705 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
9707 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
9708 qtdemux->posted_redirect = TRUE;
9711 for (i = 0; i < qtdemux->n_streams; i++) {
9712 QtDemuxStream *stream = qtdemux->streams[i];
9714 qtdemux_do_allocation (qtdemux, stream);
9717 qtdemux->exposed = TRUE;
9721 /* check if major or compatible brand is 3GP */
9722 static inline gboolean
9723 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
9726 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
9727 GST_MAKE_FOURCC ('3', 'g', 0, 0));
9728 } else if (qtdemux->comp_brands != NULL) {
9732 gboolean res = FALSE;
9734 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
9738 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
9739 GST_MAKE_FOURCC ('3', 'g', 0, 0));
9743 gst_buffer_unmap (qtdemux->comp_brands, &map);
9750 /* check if tag is a spec'ed 3GP tag keyword storing a string */
9751 static inline gboolean
9752 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
9754 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
9755 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
9756 || fourcc == FOURCC_albm;
9760 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
9761 const char *tag, const char *dummy, GNode * node)
9763 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
9767 gdouble longitude, latitude, altitude;
9770 len = QT_UINT32 (node->data);
9777 /* TODO: language code skipped */
9779 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
9782 /* do not alarm in trivial case, but bail out otherwise */
9783 if (*(data + offset) != 0) {
9784 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
9788 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
9789 GST_TAG_GEO_LOCATION_NAME, name, NULL);
9790 offset += strlen (name);
9794 if (len < offset + 2 + 4 + 4 + 4)
9797 /* +1 +1 = skip null-terminator and location role byte */
9799 /* table in spec says unsigned, semantics say negative has meaning ... */
9800 longitude = QT_SFP32 (data + offset);
9803 latitude = QT_SFP32 (data + offset);
9806 altitude = QT_SFP32 (data + offset);
9808 /* one invalid means all are invalid */
9809 if (longitude >= -180.0 && longitude <= 180.0 &&
9810 latitude >= -90.0 && latitude <= 90.0) {
9811 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
9812 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
9813 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
9814 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
9817 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
9824 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
9831 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
9832 const char *tag, const char *dummy, GNode * node)
9838 len = QT_UINT32 (node->data);
9842 y = QT_UINT16 ((guint8 *) node->data + 12);
9844 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
9847 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
9849 date = g_date_new_dmy (1, 1, y);
9850 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
9855 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
9856 const char *tag, const char *dummy, GNode * node)
9859 char *tag_str = NULL;
9864 len = QT_UINT32 (node->data);
9869 entity = (guint8 *) node->data + offset;
9870 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
9871 GST_DEBUG_OBJECT (qtdemux,
9872 "classification info: %c%c%c%c invalid classification entity",
9873 entity[0], entity[1], entity[2], entity[3]);
9878 table = QT_UINT16 ((guint8 *) node->data + offset);
9880 /* Language code skipped */
9884 /* Tag format: "XXXX://Y[YYYY]/classification info string"
9885 * XXXX: classification entity, fixed length 4 chars.
9886 * Y[YYYY]: classification table, max 5 chars.
9888 tag_str = g_strdup_printf ("----://%u/%s",
9889 table, (char *) node->data + offset);
9891 /* memcpy To be sure we're preserving byte order */
9892 memcpy (tag_str, entity, 4);
9893 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
9895 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
9904 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
9910 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
9911 const char *tag, const char *dummy, GNode * node)
9913 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
9919 gboolean ret = TRUE;
9920 const gchar *charset = NULL;
9922 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9924 len = QT_UINT32 (data->data);
9925 type = QT_UINT32 ((guint8 *) data->data + 8);
9926 if (type == 0x00000001 && len > 16) {
9927 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
9930 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
9931 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
9934 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
9938 len = QT_UINT32 (node->data);
9939 type = QT_UINT32 ((guint8 *) node->data + 4);
9940 if ((type >> 24) == 0xa9) {
9944 /* Type starts with the (C) symbol, so the next data is a list
9945 * of (string size(16), language code(16), string) */
9947 str_len = QT_UINT16 ((guint8 *) node->data + 8);
9948 lang_code = QT_UINT16 ((guint8 *) node->data + 10);
9950 /* the string + fourcc + size + 2 16bit fields,
9951 * means that there are more tags in this atom */
9952 if (len > str_len + 8 + 4) {
9953 /* TODO how to represent the same tag in different languages? */
9954 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
9955 "text alternatives, reading only first one");
9959 len = str_len + 8 + 4; /* remove trailing strings that we don't use */
9960 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
9962 if (lang_code < 0x800) { /* MAC encoded string */
9965 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
9966 QT_FOURCC ((guint8 *) node->data + 4))) {
9967 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
9969 /* we go for 3GP style encoding if major brands claims so,
9970 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
9971 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
9972 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
9973 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
9975 /* 16-bit Language code is ignored here as well */
9976 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
9983 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
9984 ret = FALSE; /* may have to fallback */
9989 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
9990 charset, NULL, NULL, &err);
9992 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
9993 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
9998 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
9999 len - offset, env_vars);
10002 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
10003 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
10007 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
10014 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
10015 const char *tag, const char *dummy, GNode * node)
10017 qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
10021 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
10022 const char *tag, const char *dummy, GNode * node)
10024 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
10026 char *s, *t, *k = NULL;
10031 /* first try normal string tag if major brand not 3GP */
10032 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
10033 if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
10034 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
10035 * let's try it 3gpp way after minor safety check */
10037 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
10043 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
10047 len = QT_UINT32 (data);
10051 count = QT_UINT8 (data + 14);
10053 for (; count; count--) {
10056 if (offset + 1 > len)
10058 slen = QT_UINT8 (data + offset);
10060 if (offset + slen > len)
10062 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
10065 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
10067 t = g_strjoin (",", k, s, NULL);
10075 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
10082 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
10083 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
10092 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
10098 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
10099 const char *tag1, const char *tag2, GNode * node)
10106 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
10108 len = QT_UINT32 (data->data);
10109 type = QT_UINT32 ((guint8 *) data->data + 8);
10110 if (type == 0x00000000 && len >= 22) {
10111 n1 = QT_UINT16 ((guint8 *) data->data + 18);
10112 n2 = QT_UINT16 ((guint8 *) data->data + 20);
10114 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
10115 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
10118 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
10119 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
10126 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
10127 const char *tag1, const char *dummy, GNode * node)
10134 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
10136 len = QT_UINT32 (data->data);
10137 type = QT_UINT32 ((guint8 *) data->data + 8);
10138 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
10139 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
10140 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
10141 n1 = QT_UINT16 ((guint8 *) data->data + 16);
10143 /* do not add bpm=0 */
10144 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
10145 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
10153 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
10154 const char *tag1, const char *dummy, GNode * node)
10161 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
10163 len = QT_UINT32 (data->data);
10164 type = QT_UINT32 ((guint8 *) data->data + 8);
10165 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
10166 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
10167 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
10168 num = QT_UINT32 ((guint8 *) data->data + 16);
10170 /* do not add num=0 */
10171 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
10172 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
10179 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
10180 const char *tag1, const char *dummy, GNode * node)
10187 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
10189 len = QT_UINT32 (data->data);
10190 type = QT_UINT32 ((guint8 *) data->data + 8);
10191 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
10192 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
10194 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
10195 len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
10196 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
10197 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
10198 gst_sample_unref (sample);
10205 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
10206 const char *tag, const char *dummy, GNode * node)
10213 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
10215 len = QT_UINT32 (data->data);
10216 type = QT_UINT32 ((guint8 *) data->data + 8);
10217 if (type == 0x00000001 && len > 16) {
10218 guint y, m = 1, d = 1;
10221 s = g_strndup ((char *) data->data + 16, len - 16);
10222 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
10223 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
10224 if (ret >= 1 && y > 1500 && y < 3000) {
10227 date = g_date_new_dmy (d, m, y);
10228 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
10229 g_date_free (date);
10231 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
10239 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
10240 const char *tag, const char *dummy, GNode * node)
10244 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
10246 /* re-route to normal string tag if major brand says so
10247 * or no data atom and compatible brand suggests so */
10248 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
10249 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
10250 qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
10255 guint len, type, n;
10257 len = QT_UINT32 (data->data);
10258 type = QT_UINT32 ((guint8 *) data->data + 8);
10259 if (type == 0x00000000 && len >= 18) {
10260 n = QT_UINT16 ((guint8 *) data->data + 16);
10262 const gchar *genre;
10264 genre = gst_tag_id3_genre_get (n - 1);
10265 if (genre != NULL) {
10266 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
10267 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
10275 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
10276 const gchar * tag, guint8 * data, guint32 datasize)
10281 /* make a copy to have \0 at the end */
10282 datacopy = g_strndup ((gchar *) data, datasize);
10284 /* convert the str to double */
10285 if (sscanf (datacopy, "%lf", &value) == 1) {
10286 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
10287 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
10289 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
10297 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
10298 const char *tag, const char *tag_bis, GNode * node)
10307 const gchar *meanstr;
10308 const gchar *namestr;
10310 /* checking the whole ---- atom size for consistency */
10311 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
10312 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
10316 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
10318 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
10322 meansize = QT_UINT32 (mean->data);
10323 if (meansize <= 12) {
10324 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
10327 meanstr = ((gchar *) mean->data) + 12;
10330 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
10332 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
10336 namesize = QT_UINT32 (name->data);
10337 if (namesize <= 12) {
10338 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
10341 namestr = ((gchar *) name->data) + 12;
10349 * uint24 - data type
10353 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
10355 GST_WARNING_OBJECT (demux, "No data atom in this tag");
10358 datasize = QT_UINT32 (data->data);
10359 if (datasize <= 16) {
10360 GST_WARNING_OBJECT (demux, "Data atom too small");
10363 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
10365 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
10366 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
10367 static const struct
10369 const gchar name[28];
10370 const gchar tag[28];
10373 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
10374 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
10375 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
10376 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
10377 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
10378 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
10379 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
10380 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
10384 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
10385 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
10386 switch (gst_tag_get_type (tags[i].tag)) {
10387 case G_TYPE_DOUBLE:
10388 qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
10389 ((guint8 *) data->data) + 16, datasize - 16);
10391 case G_TYPE_STRING:
10392 qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
10401 if (i == G_N_ELEMENTS (tags))
10411 #ifndef GST_DISABLE_GST_DEBUG
10413 gchar *namestr_dbg;
10414 gchar *meanstr_dbg;
10416 meanstr_dbg = g_strndup (meanstr, meansize);
10417 namestr_dbg = g_strndup (namestr, namesize);
10419 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
10420 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
10422 g_free (namestr_dbg);
10423 g_free (meanstr_dbg);
10430 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
10431 const char *tag_bis, GNode * node)
10436 GstTagList *id32_taglist = NULL;
10438 GST_LOG_OBJECT (demux, "parsing ID32");
10441 len = GST_READ_UINT32_BE (data);
10443 /* need at least full box and language tag */
10447 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
10448 gst_buffer_fill (buf, 0, data + 14, len - 14);
10450 id32_taglist = gst_tag_list_from_id3v2_tag (buf);
10451 if (id32_taglist) {
10452 GST_LOG_OBJECT (demux, "parsing ok");
10453 gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
10454 gst_tag_list_unref (id32_taglist);
10456 GST_LOG_OBJECT (demux, "parsing failed");
10459 gst_buffer_unref (buf);
10462 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
10463 const char *tag, const char *tag_bis, GNode * node);
10466 FOURCC_pcst -> if media is a podcast -> bool
10467 FOURCC_cpil -> if media is part of a compilation -> bool
10468 FOURCC_pgap -> if media is part of a gapless context -> bool
10469 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
10472 static const struct
10475 const gchar *gst_tag;
10476 const gchar *gst_tag_bis;
10477 const GstQTDemuxAddTagFunc func;
10480 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
10481 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
10482 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
10483 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
10484 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
10485 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
10486 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
10487 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
10488 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
10489 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
10490 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
10491 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
10492 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
10493 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
10494 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
10495 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
10496 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
10497 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
10498 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
10499 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
10500 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
10501 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
10502 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
10503 qtdemux_tag_add_num}, {
10504 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
10505 qtdemux_tag_add_num}, {
10506 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
10507 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
10508 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
10509 FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
10510 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
10511 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
10512 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
10513 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
10514 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
10515 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
10516 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
10517 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
10518 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
10519 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
10520 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
10521 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
10522 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
10523 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
10524 qtdemux_tag_add_classification}, {
10525 FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
10526 FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
10527 FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
10529 /* This is a special case, some tags are stored in this
10530 * 'reverse dns naming', according to:
10531 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
10534 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
10535 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
10536 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
10539 struct _GstQtDemuxTagList
10542 GstTagList *taglist;
10544 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
10547 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
10553 const gchar *style;
10558 GstQTDemux *demux = qtdemuxtaglist->demux;
10559 GstTagList *taglist = qtdemuxtaglist->taglist;
10562 len = QT_UINT32 (data);
10563 buf = gst_buffer_new_and_alloc (len);
10564 gst_buffer_fill (buf, 0, data, len);
10566 /* heuristic to determine style of tag */
10567 if (QT_FOURCC (data + 4) == FOURCC_____ ||
10568 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
10570 else if (demux->major_brand == FOURCC_qt__)
10571 style = "quicktime";
10572 /* fall back to assuming iso/3gp tag style */
10576 /* santize the name for the caps. */
10577 for (i = 0; i < 4; i++) {
10578 guint8 d = data[4 + i];
10579 if (g_ascii_isalnum (d))
10580 ndata[i] = g_ascii_tolower (d);
10585 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
10586 ndata[0], ndata[1], ndata[2], ndata[3]);
10587 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
10589 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
10590 sample = gst_sample_new (buf, NULL, NULL, s);
10591 gst_buffer_unref (buf);
10592 g_free (media_type);
10594 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
10597 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
10598 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
10600 gst_sample_unref (sample);
10604 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
10611 GstQtDemuxTagList demuxtaglist;
10613 demuxtaglist.demux = qtdemux;
10614 demuxtaglist.taglist = taglist;
10616 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
10617 if (meta != NULL) {
10618 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
10619 if (ilst == NULL) {
10620 GST_LOG_OBJECT (qtdemux, "no ilst");
10625 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
10629 while (i < G_N_ELEMENTS (add_funcs)) {
10630 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
10634 len = QT_UINT32 (node->data);
10636 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
10637 GST_FOURCC_ARGS (add_funcs[i].fourcc));
10639 add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
10640 add_funcs[i].gst_tag_bis, node);
10642 g_node_destroy (node);
10648 /* parsed nodes have been removed, pass along remainder as blob */
10649 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
10650 (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
10652 /* parse up XMP_ node if existing */
10653 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
10654 if (xmp_ != NULL) {
10656 GstTagList *xmptaglist;
10658 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
10659 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
10660 xmptaglist = gst_tag_list_from_xmp_buffer (buf);
10661 gst_buffer_unref (buf);
10663 qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
10665 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
10671 GstStructure *structure; /* helper for sort function */
10673 guint min_req_bitrate;
10674 guint min_req_qt_version;
10678 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
10680 GstQtReference *ref_a = (GstQtReference *) a;
10681 GstQtReference *ref_b = (GstQtReference *) b;
10683 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
10684 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
10686 /* known bitrates go before unknown; higher bitrates go first */
10687 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
10690 /* sort the redirects and post a message for the application.
10693 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
10695 GstQtReference *best;
10698 GValue list_val = { 0, };
10701 g_assert (references != NULL);
10703 references = g_list_sort (references, qtdemux_redirects_sort_func);
10705 best = (GstQtReference *) references->data;
10707 g_value_init (&list_val, GST_TYPE_LIST);
10709 for (l = references; l != NULL; l = l->next) {
10710 GstQtReference *ref = (GstQtReference *) l->data;
10711 GValue struct_val = { 0, };
10713 ref->structure = gst_structure_new ("redirect",
10714 "new-location", G_TYPE_STRING, ref->location, NULL);
10716 if (ref->min_req_bitrate > 0) {
10717 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
10718 ref->min_req_bitrate, NULL);
10721 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
10722 g_value_set_boxed (&struct_val, ref->structure);
10723 gst_value_list_append_value (&list_val, &struct_val);
10724 g_value_unset (&struct_val);
10725 /* don't free anything here yet, since we need best->structure below */
10728 g_assert (best != NULL);
10729 s = gst_structure_copy (best->structure);
10731 if (g_list_length (references) > 1) {
10732 gst_structure_set_value (s, "locations", &list_val);
10735 g_value_unset (&list_val);
10737 for (l = references; l != NULL; l = l->next) {
10738 GstQtReference *ref = (GstQtReference *) l->data;
10740 gst_structure_free (ref->structure);
10741 g_free (ref->location);
10744 g_list_free (references);
10746 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
10747 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
10748 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
10749 qtdemux->posted_redirect = TRUE;
10752 /* look for redirect nodes, collect all redirect information and
10756 qtdemux_parse_redirects (GstQTDemux * qtdemux)
10758 GNode *rmra, *rmda, *rdrf;
10760 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
10762 GList *redirects = NULL;
10764 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
10766 GstQtReference ref = { NULL, NULL, 0, 0 };
10767 GNode *rmdr, *rmvc;
10769 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
10770 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
10771 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
10772 ref.min_req_bitrate);
10775 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
10776 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
10777 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
10779 #ifndef GST_DISABLE_GST_DEBUG
10780 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
10782 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
10784 GST_LOG_OBJECT (qtdemux,
10785 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
10786 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
10787 bitmask, check_type);
10788 if (package == FOURCC_qtim && check_type == 0) {
10789 ref.min_req_qt_version = version;
10793 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
10799 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
10800 if (ref_len > 20) {
10801 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
10802 ref_data = (guint8 *) rdrf->data + 20;
10803 if (ref_type == FOURCC_alis) {
10804 guint record_len, record_version, fn_len;
10806 if (ref_len > 70) {
10807 /* MacOSX alias record, google for alias-layout.txt */
10808 record_len = QT_UINT16 (ref_data + 4);
10809 record_version = QT_UINT16 (ref_data + 4 + 2);
10810 fn_len = QT_UINT8 (ref_data + 50);
10811 if (record_len > 50 && record_version == 2 && fn_len > 0) {
10812 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
10815 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
10818 } else if (ref_type == FOURCC_url_) {
10819 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
10821 GST_DEBUG_OBJECT (qtdemux,
10822 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
10823 GST_FOURCC_ARGS (ref_type));
10825 if (ref.location != NULL) {
10826 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
10828 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
10830 GST_WARNING_OBJECT (qtdemux,
10831 "Failed to extract redirect location from rdrf atom");
10834 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
10838 /* look for others */
10839 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
10842 if (redirects != NULL) {
10843 qtdemux_process_redirects (qtdemux, redirects);
10849 static GstTagList *
10850 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
10854 if (tags == NULL) {
10855 tags = gst_tag_list_new_empty ();
10856 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
10859 if (qtdemux->major_brand == FOURCC_mjp2)
10860 fmt = "Motion JPEG 2000";
10861 else if ((qtdemux->major_brand & 0xffff) == GST_MAKE_FOURCC ('3', 'g', 0, 0))
10863 else if (qtdemux->major_brand == FOURCC_qt__)
10865 else if (qtdemux->fragmented)
10868 fmt = "ISO MP4/M4A";
10870 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
10871 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
10873 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
10879 /* we have read th complete moov node now.
10880 * This function parses all of the relevant info, creates the traks and
10881 * prepares all data structures for playback
10884 qtdemux_parse_tree (GstQTDemux * qtdemux)
10890 GstClockTime duration;
10891 guint64 creation_time;
10892 GstDateTime *datetime = NULL;
10895 /* make sure we have a usable taglist */
10896 if (!qtdemux->tag_list) {
10897 qtdemux->tag_list = gst_tag_list_new_empty ();
10898 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
10900 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
10903 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
10904 if (mvhd == NULL) {
10905 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
10906 return qtdemux_parse_redirects (qtdemux);
10909 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
10910 if (version == 1) {
10911 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
10912 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
10913 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
10914 } else if (version == 0) {
10915 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
10916 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
10917 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
10919 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
10923 /* Moving qt creation time (secs since 1904) to unix time */
10924 if (creation_time != 0) {
10925 /* Try to use epoch first as it should be faster and more commonly found */
10926 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
10929 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
10930 /* some data cleansing sanity */
10931 g_get_current_time (&now);
10932 if (now.tv_sec + 24 * 3600 < creation_time) {
10933 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
10935 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
10938 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
10939 GDateTime *dt, *dt_local;
10941 dt = g_date_time_add_seconds (base_dt, creation_time);
10942 dt_local = g_date_time_to_local (dt);
10943 datetime = gst_date_time_new_from_g_date_time (dt_local);
10945 g_date_time_unref (base_dt);
10946 g_date_time_unref (dt);
10950 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
10951 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
10953 gst_date_time_unref (datetime);
10956 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
10957 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
10959 /* check for fragmented file and get some (default) data */
10960 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
10963 GstByteReader mehd_data;
10965 /* let track parsing or anyone know weird stuff might happen ... */
10966 qtdemux->fragmented = TRUE;
10968 /* compensate for total duration */
10969 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
10971 qtdemux_parse_mehd (qtdemux, &mehd_data);
10974 /* set duration in the segment info */
10975 gst_qtdemux_get_duration (qtdemux, &duration);
10977 qtdemux->segment.duration = duration;
10978 /* also do not exceed duration; stop is set that way post seek anyway,
10979 * and segment activation falls back to duration,
10980 * whereas loop only checks stop, so let's align this here as well */
10981 qtdemux->segment.stop = duration;
10984 /* parse all traks */
10985 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
10987 qtdemux_parse_trak (qtdemux, trak);
10988 /* iterate all siblings */
10989 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
10992 if (!qtdemux->tag_list) {
10993 GST_DEBUG_OBJECT (qtdemux, "new tag list");
10994 qtdemux->tag_list = gst_tag_list_new_empty ();
10995 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
10997 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
11001 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
11003 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
11005 GST_LOG_OBJECT (qtdemux, "No udta node found.");
11008 /* maybe also some tags in meta box */
11009 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
11011 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
11012 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
11014 GST_LOG_OBJECT (qtdemux, "No meta node found.");
11017 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
11022 /* taken from ffmpeg */
11024 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
11036 len = (len << 7) | (c & 0x7f);
11044 /* this can change the codec originally present in @list */
11046 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
11047 GNode * esds, GstTagList * list)
11049 int len = QT_UINT32 (esds->data);
11050 guint8 *ptr = esds->data;
11051 guint8 *end = ptr + len;
11053 guint8 *data_ptr = NULL;
11055 guint8 object_type_id = 0;
11056 const char *codec_name = NULL;
11057 GstCaps *caps = NULL;
11059 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
11061 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
11063 while (ptr + 1 < end) {
11064 tag = QT_UINT8 (ptr);
11065 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
11067 len = read_descr_size (ptr, end, &ptr);
11068 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
11070 /* Check the stated amount of data is available for reading */
11071 if (len < 0 || ptr + len > end)
11075 case ES_DESCRIPTOR_TAG:
11076 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
11077 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
11080 case DECODER_CONFIG_DESC_TAG:{
11081 guint max_bitrate, avg_bitrate;
11083 object_type_id = QT_UINT8 (ptr);
11084 max_bitrate = QT_UINT32 (ptr + 5);
11085 avg_bitrate = QT_UINT32 (ptr + 9);
11086 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
11087 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
11088 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
11089 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
11090 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
11091 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
11092 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
11093 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
11095 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
11096 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
11097 avg_bitrate, NULL);
11102 case DECODER_SPECIFIC_INFO_TAG:
11103 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
11104 if (object_type_id == 0xe0 && len == 0x40) {
11110 GST_DEBUG_OBJECT (qtdemux,
11111 "Have VOBSUB palette. Creating palette event");
11112 /* move to decConfigDescr data and read palette */
11114 for (i = 0; i < 16; i++) {
11115 clut[i] = QT_UINT32 (data);
11119 s = gst_structure_new ("application/x-gst-dvd", "event",
11120 G_TYPE_STRING, "dvd-spu-clut-change",
11121 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
11122 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
11123 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
11124 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
11125 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
11126 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
11127 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
11128 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
11131 /* store event and trigger custom processing */
11132 stream->pending_event =
11133 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
11135 /* Generic codec_data handler puts it on the caps */
11142 case SL_CONFIG_DESC_TAG:
11143 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
11147 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
11149 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
11155 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
11156 * in use, and should also be used to override some other parameters for some
11158 switch (object_type_id) {
11159 case 0x20: /* MPEG-4 */
11160 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
11161 * profile_and_level_indication */
11162 if (data_ptr != NULL && data_len >= 5 &&
11163 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
11164 gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
11165 data_ptr + 4, data_len - 4);
11167 break; /* Nothing special needed here */
11168 case 0x21: /* H.264 */
11169 codec_name = "H.264 / AVC";
11170 caps = gst_caps_new_simple ("video/x-h264",
11171 "stream-format", G_TYPE_STRING, "avc",
11172 "alignment", G_TYPE_STRING, "au", NULL);
11174 case 0x40: /* AAC (any) */
11175 case 0x66: /* AAC Main */
11176 case 0x67: /* AAC LC */
11177 case 0x68: /* AAC SSR */
11178 /* Override channels and rate based on the codec_data, as it's often
11180 /* Only do so for basic setup without HE-AAC extension */
11181 if (data_ptr && data_len == 2) {
11182 guint channels, rateindex, rate;
11184 /* FIXME: add gst_codec_utils_aac_get_{channels|sample_rate}()? */
11185 channels = (data_ptr[1] & 0x7f) >> 3;
11186 if (channels > 0 && channels < 7) {
11187 stream->n_channels = channels;
11188 } else if (channels == 7) {
11189 stream->n_channels = 8;
11192 rateindex = ((data_ptr[0] & 0x7) << 1) | ((data_ptr[1] & 0x80) >> 7);
11193 rate = gst_codec_utils_aac_get_sample_rate_from_index (rateindex);
11195 stream->rate = rate;
11198 /* Set level and profile if possible */
11199 if (data_ptr != NULL && data_len >= 2) {
11200 gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
11201 data_ptr, data_len);
11204 case 0x60: /* MPEG-2, various profiles */
11210 codec_name = "MPEG-2 video";
11211 caps = gst_caps_new_simple ("video/mpeg",
11212 "mpegversion", G_TYPE_INT, 2,
11213 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11215 case 0x69: /* MPEG-2 BC audio */
11216 case 0x6B: /* MPEG-1 audio */
11217 caps = gst_caps_new_simple ("audio/mpeg",
11218 "mpegversion", G_TYPE_INT, 1, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
11219 codec_name = "MPEG-1 audio";
11221 case 0x6A: /* MPEG-1 */
11222 codec_name = "MPEG-1 video";
11223 caps = gst_caps_new_simple ("video/mpeg",
11224 "mpegversion", G_TYPE_INT, 1,
11225 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11227 case 0x6C: /* MJPEG */
11229 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
11231 codec_name = "Motion-JPEG";
11233 case 0x6D: /* PNG */
11235 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
11237 codec_name = "PNG still images";
11239 case 0x6E: /* JPEG2000 */
11240 codec_name = "JPEG-2000";
11241 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
11243 case 0xA4: /* Dirac */
11244 codec_name = "Dirac";
11245 caps = gst_caps_new_empty_simple ("video/x-dirac");
11247 case 0xA5: /* AC3 */
11248 codec_name = "AC-3 audio";
11249 caps = gst_caps_new_simple ("audio/x-ac3",
11250 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
11252 case 0xA9: /* AC3 */
11253 codec_name = "DTS audio";
11254 caps = gst_caps_new_simple ("audio/x-dts",
11255 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
11257 case 0xE1: /* QCELP */
11258 /* QCELP, the codec_data is a riff tag (little endian) with
11259 * 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). */
11260 caps = gst_caps_new_empty_simple ("audio/qcelp");
11261 codec_name = "QCELP";
11267 /* If we have a replacement caps, then change our caps for this stream */
11269 gst_caps_unref (stream->caps);
11270 stream->caps = caps;
11273 if (codec_name && list)
11274 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
11275 GST_TAG_AUDIO_CODEC, codec_name, NULL);
11277 /* Add the codec_data attribute to caps, if we have it */
11281 buffer = gst_buffer_new_and_alloc (data_len);
11282 gst_buffer_fill (buffer, 0, data_ptr, data_len);
11284 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
11285 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
11287 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
11289 gst_buffer_unref (buffer);
11294 #define _codec(name) \
11296 if (codec_name) { \
11297 *codec_name = g_strdup (name); \
11302 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
11303 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
11305 GstCaps *caps = NULL;
11306 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
11309 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
11310 _codec ("PNG still images");
11311 caps = gst_caps_new_empty_simple ("image/png");
11313 case GST_MAKE_FOURCC ('j', 'p', 'e', 'g'):
11314 _codec ("JPEG still images");
11316 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
11319 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
11320 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
11321 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
11322 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
11323 _codec ("Motion-JPEG");
11325 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
11328 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
11329 _codec ("Motion-JPEG format B");
11330 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
11332 case GST_MAKE_FOURCC ('m', 'j', 'p', '2'):
11333 _codec ("JPEG-2000");
11334 /* override to what it should be according to spec, avoid palette_data */
11335 stream->bits_per_sample = 24;
11336 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
11338 case GST_MAKE_FOURCC ('S', 'V', 'Q', '3'):
11339 _codec ("Sorensen video v.3");
11340 caps = gst_caps_new_simple ("video/x-svq",
11341 "svqversion", G_TYPE_INT, 3, NULL);
11343 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
11344 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
11345 _codec ("Sorensen video v.1");
11346 caps = gst_caps_new_simple ("video/x-svq",
11347 "svqversion", G_TYPE_INT, 1, NULL);
11349 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
11350 caps = gst_caps_new_empty_simple ("video/x-raw");
11351 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
11352 _codec ("Windows Raw RGB");
11354 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
11358 bps = QT_UINT16 (stsd_data + 98);
11361 format = GST_VIDEO_FORMAT_RGB15;
11364 format = GST_VIDEO_FORMAT_RGB16;
11367 format = GST_VIDEO_FORMAT_RGB;
11370 format = GST_VIDEO_FORMAT_ARGB;
11378 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
11379 format = GST_VIDEO_FORMAT_I420;
11381 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
11382 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
11383 format = GST_VIDEO_FORMAT_I420;
11385 case GST_MAKE_FOURCC ('2', 'v', 'u', 'y'):
11386 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
11387 format = GST_VIDEO_FORMAT_UYVY;
11389 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
11390 format = GST_VIDEO_FORMAT_v308;
11392 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
11393 format = GST_VIDEO_FORMAT_v216;
11395 case GST_MAKE_FOURCC ('v', '2', '1', '0'):
11396 format = GST_VIDEO_FORMAT_v210;
11398 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
11399 format = GST_VIDEO_FORMAT_r210;
11401 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
11402 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
11403 format = GST_VIDEO_FORMAT_v410;
11406 /* Packed YUV 4:4:4:4 8 bit in 32 bits
11407 * but different order than AYUV
11408 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
11409 format = GST_VIDEO_FORMAT_v408;
11412 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
11413 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
11414 _codec ("MPEG-1 video");
11415 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
11416 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11418 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
11419 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
11420 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
11421 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
11422 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
11423 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
11424 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
11425 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
11426 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
11427 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
11428 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
11429 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
11430 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
11431 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
11432 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
11433 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
11434 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
11435 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
11436 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
11437 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
11438 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
11439 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
11440 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
11441 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
11442 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
11443 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
11444 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
11445 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
11446 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
11447 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
11448 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
11449 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
11450 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
11451 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
11452 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
11453 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
11454 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
11455 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
11456 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
11457 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
11458 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
11459 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
11460 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
11461 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
11462 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
11463 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
11464 _codec ("MPEG-2 video");
11465 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
11466 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11468 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
11469 _codec ("GIF still images");
11470 caps = gst_caps_new_empty_simple ("image/gif");
11472 case GST_MAKE_FOURCC ('h', '2', '6', '3'):
11473 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
11474 case GST_MAKE_FOURCC ('s', '2', '6', '3'):
11475 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
11477 /* ffmpeg uses the height/width props, don't know why */
11478 caps = gst_caps_new_simple ("video/x-h263",
11479 "variant", G_TYPE_STRING, "itu", NULL);
11481 case GST_MAKE_FOURCC ('m', 'p', '4', 'v'):
11482 case GST_MAKE_FOURCC ('M', 'P', '4', 'V'):
11483 _codec ("MPEG-4 video");
11484 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
11485 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11487 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
11488 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
11489 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
11490 caps = gst_caps_new_simple ("video/x-msmpeg",
11491 "msmpegversion", G_TYPE_INT, 43, NULL);
11493 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
11495 caps = gst_caps_new_simple ("video/x-divx",
11496 "divxversion", G_TYPE_INT, 3, NULL);
11498 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
11499 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
11501 caps = gst_caps_new_simple ("video/x-divx",
11502 "divxversion", G_TYPE_INT, 4, NULL);
11504 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
11506 caps = gst_caps_new_simple ("video/x-divx",
11507 "divxversion", G_TYPE_INT, 5, NULL);
11510 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
11511 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
11512 case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
11513 case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
11514 case GST_MAKE_FOURCC ('F', 'M', 'P', '4'):
11515 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
11516 caps = gst_caps_new_simple ("video/mpeg",
11517 "mpegversion", G_TYPE_INT, 4, NULL);
11519 *codec_name = g_strdup ("MPEG-4");
11522 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
11523 _codec ("Cinepak");
11524 caps = gst_caps_new_empty_simple ("video/x-cinepak");
11526 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
11527 _codec ("Apple QuickDraw");
11528 caps = gst_caps_new_empty_simple ("video/x-qdrw");
11530 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
11531 _codec ("Apple video");
11532 caps = gst_caps_new_empty_simple ("video/x-apple-video");
11534 case GST_MAKE_FOURCC ('H', '2', '6', '4'):
11535 case GST_MAKE_FOURCC ('a', 'v', 'c', '1'):
11536 _codec ("H.264 / AVC");
11537 caps = gst_caps_new_simple ("video/x-h264",
11538 "stream-format", G_TYPE_STRING, "avc",
11539 "alignment", G_TYPE_STRING, "au", NULL);
11541 case GST_MAKE_FOURCC ('a', 'v', 'c', '3'):
11542 _codec ("H.264 / AVC");
11543 caps = gst_caps_new_simple ("video/x-h264",
11544 "stream-format", G_TYPE_STRING, "avc3",
11545 "alignment", G_TYPE_STRING, "au", NULL);
11547 case GST_MAKE_FOURCC ('H', '2', '6', '5'):
11548 case GST_MAKE_FOURCC ('h', 'v', 'c', '1'):
11549 _codec ("H.265 / HEVC");
11550 caps = gst_caps_new_simple ("video/x-h265",
11551 "stream-format", G_TYPE_STRING, "hvc1",
11552 "alignment", G_TYPE_STRING, "au", NULL);
11554 case GST_MAKE_FOURCC ('h', 'e', 'v', '1'):
11555 _codec ("H.265 / HEVC");
11556 caps = gst_caps_new_simple ("video/x-h265",
11557 "stream-format", G_TYPE_STRING, "hev1",
11558 "alignment", G_TYPE_STRING, "au", NULL);
11560 case GST_MAKE_FOURCC ('r', 'l', 'e', ' '):
11561 _codec ("Run-length encoding");
11562 caps = gst_caps_new_simple ("video/x-rle",
11563 "layout", G_TYPE_STRING, "quicktime", NULL);
11565 case GST_MAKE_FOURCC ('W', 'R', 'L', 'E'):
11566 _codec ("Run-length encoding");
11567 caps = gst_caps_new_simple ("video/x-rle",
11568 "layout", G_TYPE_STRING, "microsoft", NULL);
11570 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
11571 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
11572 _codec ("Indeo Video 3");
11573 caps = gst_caps_new_simple ("video/x-indeo",
11574 "indeoversion", G_TYPE_INT, 3, NULL);
11576 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
11577 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
11578 _codec ("Intel Video 4");
11579 caps = gst_caps_new_simple ("video/x-indeo",
11580 "indeoversion", G_TYPE_INT, 4, NULL);
11582 case GST_MAKE_FOURCC ('d', 'v', 'c', 'p'):
11583 case GST_MAKE_FOURCC ('d', 'v', 'c', ' '):
11584 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
11585 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
11586 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
11587 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
11588 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
11589 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
11590 _codec ("DV Video");
11591 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
11592 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11594 case GST_MAKE_FOURCC ('d', 'v', '5', 'n'): /* DVCPRO50 NTSC */
11595 case GST_MAKE_FOURCC ('d', 'v', '5', 'p'): /* DVCPRO50 PAL */
11596 _codec ("DVCPro50 Video");
11597 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
11598 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11600 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
11601 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
11602 _codec ("DVCProHD Video");
11603 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
11604 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11606 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
11607 _codec ("Apple Graphics (SMC)");
11608 caps = gst_caps_new_empty_simple ("video/x-smc");
11610 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
11612 caps = gst_caps_new_empty_simple ("video/x-vp3");
11614 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
11615 _codec ("VP6 Flash");
11616 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
11618 case GST_MAKE_FOURCC ('X', 'i', 'T', 'h'):
11620 caps = gst_caps_new_empty_simple ("video/x-theora");
11621 /* theora uses one byte of padding in the data stream because it does not
11622 * allow 0 sized packets while theora does */
11623 stream->padding = 1;
11625 case GST_MAKE_FOURCC ('d', 'r', 'a', 'c'):
11627 caps = gst_caps_new_empty_simple ("video/x-dirac");
11629 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
11630 _codec ("TIFF still images");
11631 caps = gst_caps_new_empty_simple ("image/tiff");
11633 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
11634 _codec ("Apple Intermediate Codec");
11635 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
11637 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
11638 _codec ("AVID DNxHD");
11639 caps = gst_caps_from_string ("video/x-dnxhd");
11641 case GST_MAKE_FOURCC ('V', 'P', '8', '0'):
11642 _codec ("On2 VP8");
11643 caps = gst_caps_from_string ("video/x-vp8");
11645 case GST_MAKE_FOURCC ('a', 'p', 'c', 's'):
11646 _codec ("Apple ProRes LT");
11648 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
11651 case GST_MAKE_FOURCC ('a', 'p', 'c', 'h'):
11652 _codec ("Apple ProRes HQ");
11654 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
11657 case GST_MAKE_FOURCC ('a', 'p', 'c', 'n'):
11658 _codec ("Apple ProRes");
11660 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
11663 case GST_MAKE_FOURCC ('a', 'p', 'c', 'o'):
11664 _codec ("Apple ProRes Proxy");
11666 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
11669 case GST_MAKE_FOURCC ('a', 'p', '4', 'h'):
11670 _codec ("Apple ProRes 4444");
11672 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
11675 case GST_MAKE_FOURCC ('v', 'c', '-', '1'):
11678 caps = gst_caps_new_simple ("video/x-wmv",
11679 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
11681 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
11684 char *s, fourstr[5];
11686 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11687 s = g_strdup_printf ("video/x-gst-fourcc-%s", g_strstrip (fourstr));
11688 caps = gst_caps_new_empty_simple (s);
11693 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
11696 gst_video_info_init (&info);
11697 gst_video_info_set_format (&info, format, stream->width, stream->height);
11699 caps = gst_video_info_to_caps (&info);
11700 *codec_name = gst_pb_utils_get_codec_description (caps);
11702 /* enable clipping for raw video streams */
11703 stream->need_clip = TRUE;
11710 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
11711 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
11714 const GstStructure *s;
11718 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
11721 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
11722 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
11723 _codec ("Raw 8-bit PCM audio");
11724 caps = gst_caps_new_simple ("audio/x-raw",
11725 "format", G_TYPE_STRING, "U8",
11726 "layout", G_TYPE_STRING, "interleaved", NULL);
11728 case GST_MAKE_FOURCC ('t', 'w', 'o', 's'):
11729 endian = G_BIG_ENDIAN;
11731 case GST_MAKE_FOURCC ('s', 'o', 'w', 't'):
11735 GstAudioFormat format;
11738 endian = G_LITTLE_ENDIAN;
11740 depth = stream->bytes_per_packet * 8;
11741 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
11743 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
11747 caps = gst_caps_new_simple ("audio/x-raw",
11748 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
11749 "layout", G_TYPE_STRING, "interleaved", NULL);
11752 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
11753 _codec ("Raw 64-bit floating-point audio");
11754 caps = gst_caps_new_simple ("audio/x-raw",
11755 "format", G_TYPE_STRING, "F64BE",
11756 "layout", G_TYPE_STRING, "interleaved", NULL);
11758 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
11759 _codec ("Raw 32-bit floating-point audio");
11760 caps = gst_caps_new_simple ("audio/x-raw",
11761 "format", G_TYPE_STRING, "F32BE",
11762 "layout", G_TYPE_STRING, "interleaved", NULL);
11765 _codec ("Raw 24-bit PCM audio");
11766 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
11768 caps = gst_caps_new_simple ("audio/x-raw",
11769 "format", G_TYPE_STRING, "S24BE",
11770 "layout", G_TYPE_STRING, "interleaved", NULL);
11772 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
11773 _codec ("Raw 32-bit PCM audio");
11774 caps = gst_caps_new_simple ("audio/x-raw",
11775 "format", G_TYPE_STRING, "S32BE",
11776 "layout", G_TYPE_STRING, "interleaved", NULL);
11778 case GST_MAKE_FOURCC ('u', 'l', 'a', 'w'):
11779 _codec ("Mu-law audio");
11780 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
11782 case GST_MAKE_FOURCC ('a', 'l', 'a', 'w'):
11783 _codec ("A-law audio");
11784 caps = gst_caps_new_empty_simple ("audio/x-alaw");
11788 _codec ("Microsoft ADPCM");
11789 /* Microsoft ADPCM-ACM code 2 */
11790 caps = gst_caps_new_simple ("audio/x-adpcm",
11791 "layout", G_TYPE_STRING, "microsoft", NULL);
11795 _codec ("DVI/IMA ADPCM");
11796 caps = gst_caps_new_simple ("audio/x-adpcm",
11797 "layout", G_TYPE_STRING, "dvi", NULL);
11801 _codec ("DVI/Intel IMA ADPCM");
11802 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
11803 caps = gst_caps_new_simple ("audio/x-adpcm",
11804 "layout", G_TYPE_STRING, "quicktime", NULL);
11808 /* MPEG layer 3, CBR only (pre QT4.1) */
11809 case GST_MAKE_FOURCC ('.', 'm', 'p', '3'):
11810 _codec ("MPEG-1 layer 3");
11811 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
11812 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
11813 "mpegversion", G_TYPE_INT, 1, NULL);
11816 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
11817 _codec ("EAC-3 audio");
11818 caps = gst_caps_new_simple ("audio/x-eac3",
11819 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
11820 stream->sampled = TRUE;
11822 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
11823 case GST_MAKE_FOURCC ('a', 'c', '-', '3'):
11824 _codec ("AC-3 audio");
11825 caps = gst_caps_new_simple ("audio/x-ac3",
11826 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
11827 stream->sampled = TRUE;
11829 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
11830 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
11831 _codec ("DTS audio");
11832 caps = gst_caps_new_simple ("audio/x-dts",
11833 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
11834 stream->sampled = TRUE;
11836 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
11837 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
11838 _codec ("DTS-HD audio");
11839 caps = gst_caps_new_simple ("audio/x-dts",
11840 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
11841 stream->sampled = TRUE;
11843 case GST_MAKE_FOURCC ('M', 'A', 'C', '3'):
11845 caps = gst_caps_new_simple ("audio/x-mace",
11846 "maceversion", G_TYPE_INT, 3, NULL);
11848 case GST_MAKE_FOURCC ('M', 'A', 'C', '6'):
11850 caps = gst_caps_new_simple ("audio/x-mace",
11851 "maceversion", G_TYPE_INT, 6, NULL);
11853 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
11855 caps = gst_caps_new_empty_simple ("application/ogg");
11857 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
11858 _codec ("DV audio");
11859 caps = gst_caps_new_empty_simple ("audio/x-dv");
11861 case GST_MAKE_FOURCC ('m', 'p', '4', 'a'):
11862 _codec ("MPEG-4 AAC audio");
11863 caps = gst_caps_new_simple ("audio/mpeg",
11864 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
11865 "stream-format", G_TYPE_STRING, "raw", NULL);
11867 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
11868 _codec ("QDesign Music");
11869 caps = gst_caps_new_empty_simple ("audio/x-qdm");
11871 case GST_MAKE_FOURCC ('Q', 'D', 'M', '2'):
11872 _codec ("QDesign Music v.2");
11873 /* FIXME: QDesign music version 2 (no constant) */
11874 if (FALSE && data) {
11875 caps = gst_caps_new_simple ("audio/x-qdm2",
11876 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
11877 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
11878 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
11880 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
11883 case GST_MAKE_FOURCC ('a', 'g', 's', 'm'):
11884 _codec ("GSM audio");
11885 caps = gst_caps_new_empty_simple ("audio/x-gsm");
11887 case GST_MAKE_FOURCC ('s', 'a', 'm', 'r'):
11888 _codec ("AMR audio");
11889 caps = gst_caps_new_empty_simple ("audio/AMR");
11891 case GST_MAKE_FOURCC ('s', 'a', 'w', 'b'):
11892 _codec ("AMR-WB audio");
11893 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
11895 case GST_MAKE_FOURCC ('i', 'm', 'a', '4'):
11896 _codec ("Quicktime IMA ADPCM");
11897 caps = gst_caps_new_simple ("audio/x-adpcm",
11898 "layout", G_TYPE_STRING, "quicktime", NULL);
11900 case GST_MAKE_FOURCC ('a', 'l', 'a', 'c'):
11901 _codec ("Apple lossless audio");
11902 caps = gst_caps_new_empty_simple ("audio/x-alac");
11904 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
11905 _codec ("QualComm PureVoice");
11906 caps = gst_caps_from_string ("audio/qcelp");
11908 case GST_MAKE_FOURCC ('w', 'm', 'a', ' '):
11911 caps = gst_caps_new_empty_simple ("audio/x-wma");
11913 case GST_MAKE_FOURCC ('l', 'p', 'c', 'm'):
11918 GstAudioFormat format;
11921 FLAG_IS_FLOAT = 0x1,
11922 FLAG_IS_BIG_ENDIAN = 0x2,
11923 FLAG_IS_SIGNED = 0x4,
11924 FLAG_IS_PACKED = 0x8,
11925 FLAG_IS_ALIGNED_HIGH = 0x10,
11926 FLAG_IS_NON_INTERLEAVED = 0x20
11928 _codec ("Raw LPCM audio");
11930 if (data && len >= 56) {
11931 depth = QT_UINT32 (data + 40);
11932 flags = QT_UINT32 (data + 44);
11933 width = QT_UINT32 (data + 48) * 8 / stream->n_channels;
11935 if ((flags & FLAG_IS_FLOAT) == 0) {
11940 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
11941 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
11942 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
11943 caps = gst_caps_new_simple ("audio/x-raw",
11944 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
11945 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
11946 "non-interleaved" : "interleaved", NULL);
11951 if (flags & FLAG_IS_BIG_ENDIAN)
11952 format = GST_AUDIO_FORMAT_F64BE;
11954 format = GST_AUDIO_FORMAT_F64LE;
11956 if (flags & FLAG_IS_BIG_ENDIAN)
11957 format = GST_AUDIO_FORMAT_F32BE;
11959 format = GST_AUDIO_FORMAT_F32LE;
11961 caps = gst_caps_new_simple ("audio/x-raw",
11962 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
11963 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
11964 "non-interleaved" : "interleaved", NULL);
11968 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
11972 char *s, fourstr[5];
11974 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11975 s = g_strdup_printf ("audio/x-gst-fourcc-%s", g_strstrip (fourstr));
11976 caps = gst_caps_new_empty_simple (s);
11982 GstCaps *templ_caps =
11983 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
11984 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
11985 gst_caps_unref (caps);
11986 gst_caps_unref (templ_caps);
11987 caps = intersection;
11990 /* enable clipping for raw audio streams */
11991 s = gst_caps_get_structure (caps, 0);
11992 name = gst_structure_get_name (s);
11993 if (g_str_has_prefix (name, "audio/x-raw")) {
11994 stream->need_clip = TRUE;
11995 stream->max_buffer_size = 4096 * stream->bytes_per_frame;
11996 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
12002 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
12003 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
12007 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
12010 case GST_MAKE_FOURCC ('m', 'p', '4', 's'):
12011 _codec ("DVD subtitle");
12012 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
12013 stream->need_process = TRUE;
12015 case GST_MAKE_FOURCC ('t', 'e', 'x', 't'):
12016 _codec ("Quicktime timed text");
12018 case GST_MAKE_FOURCC ('t', 'x', '3', 'g'):
12019 _codec ("3GPP timed text");
12021 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
12023 /* actual text piece needs to be extracted */
12024 stream->need_process = TRUE;
12028 char *s, fourstr[5];
12030 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12031 s = g_strdup_printf ("text/x-gst-fourcc-%s", g_strstrip (fourstr));
12032 caps = gst_caps_new_empty_simple (s);
12040 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
12041 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
12046 case GST_MAKE_FOURCC ('m', '1', 'v', ' '):
12047 _codec ("MPEG 1 video");
12048 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
12049 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);