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
11 * Copyright (C) <2015> YouView TV Ltd.
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Library General Public
15 * License as published by the Free Software Foundation; either
16 * version 2 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Library General Public License for more details.
23 * You should have received a copy of the GNU Library General Public
24 * License along with this library; if not, write to the
25 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
26 * Boston, MA 02110-1301, USA.
30 * SECTION:element-qtdemux
32 * Demuxes a .mov file into raw or compressed audio and/or video streams.
34 * This element supports both push and pull-based scheduling, depending on the
35 * capabilities of the upstream elements.
38 * <title>Example launch line</title>
40 * 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
41 * ]| Play (parse and decode) a .mov file and try to output it to
42 * an automatically detected soundcard and videosink. If the MOV file contains
43 * compressed audio or video data, this will only work if you have the
44 * right decoder elements/plugins installed.
52 #include "gst/gst-i18n-plugin.h"
54 #include <glib/gprintf.h>
55 #include <gst/tag/tag.h>
56 #include <gst/audio/audio.h>
57 #include <gst/video/video.h>
59 #include "qtatomparser.h"
60 #include "qtdemux_types.h"
61 #include "qtdemux_dump.h"
63 #include "descriptors.h"
64 #include "qtdemux_lang.h"
66 #include "qtpalette.h"
68 #include "gst/riff/riff-media.h"
69 #include "gst/riff/riff-read.h"
71 #include <gst/pbutils/pbutils.h>
78 #include <gst/math-compat.h>
84 /* max. size considered 'sane' for non-mdat atoms */
85 #define QTDEMUX_MAX_ATOM_SIZE (25*1024*1024)
87 /* if the sample index is larger than this, something is likely wrong */
88 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (50*1024*1024)
90 /* For converting qt creation times to unix epoch times */
91 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
92 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
93 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
94 QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
96 #define STREAM_IS_EOS(s) (s->time_position == GST_CLOCK_TIME_NONE)
98 GST_DEBUG_CATEGORY (qtdemux_debug);
100 /*typedef struct _QtNode QtNode; */
101 typedef struct _QtDemuxSegment QtDemuxSegment;
102 typedef struct _QtDemuxSample QtDemuxSample;
104 typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo;
113 struct _QtDemuxSample
116 gint32 pts_offset; /* Add this value to timestamp to get the pts */
118 guint64 timestamp; /* DTS In mov time */
119 guint32 duration; /* In mov time */
120 gboolean keyframe; /* TRUE when this packet is a keyframe */
123 /* Macros for converting to/from timescale */
124 #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale))
125 #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND))
127 #define QTTIME_TO_GSTTIME(qtdemux, value) (gst_util_uint64_scale((value), GST_SECOND, (qtdemux)->timescale))
128 #define GSTTIME_TO_QTTIME(qtdemux, value) (gst_util_uint64_scale((value), (qtdemux)->timescale, GST_SECOND))
130 /* timestamp is the DTS */
131 #define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp))
132 /* timestamp + offset is the PTS */
133 #define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (stream)->cslg_shift + (sample)->pts_offset))
134 /* timestamp + duration - dts is the duration */
135 #define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts))
137 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
140 * Quicktime has tracks and segments. A track is a continuous piece of
141 * multimedia content. The track is not always played from start to finish but
142 * instead, pieces of the track are 'cut out' and played in sequence. This is
143 * what the segments do.
145 * Inside the track we have keyframes (K) and delta frames. The track has its
146 * own timing, which starts from 0 and extends to end. The position in the track
147 * is called the media_time.
149 * The segments now describe the pieces that should be played from this track
150 * and are basically tuples of media_time/duration/rate entries. We can have
151 * multiple segments and they are all played after one another. An example:
153 * segment 1: media_time: 1 second, duration: 1 second, rate 1
154 * segment 2: media_time: 3 second, duration: 2 second, rate 2
156 * To correctly play back this track, one must play: 1 second of media starting
157 * from media_time 1 followed by 2 seconds of media starting from media_time 3
160 * Each of the segments will be played at a specific time, the first segment at
161 * time 0, the second one after the duration of the first one, etc.. Note that
162 * the time in resulting playback is not identical to the media_time of the
165 * Visually, assuming the track has 4 second of media_time:
168 * .-----------------------------------------------------------.
169 * track: | K.....K.........K........K.......K.......K...........K... |
170 * '-----------------------------------------------------------'
172 * .------------^ ^ .----------^ ^
173 * / .-------------' / .------------------'
175 * .--------------. .--------------.
176 * | segment 1 | | segment 2 |
177 * '--------------' '--------------'
179 * The challenge here is to cut out the right pieces of the track for each of
180 * the playback segments. This fortunately can easily be done with the SEGMENT
181 * events of GStreamer.
183 * For playback of segment 1, we need to provide the decoder with the keyframe
184 * (a), in the above figure, but we must instruct it only to output the decoded
185 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
186 * position set to the time of the segment: 0.
188 * We then proceed to push data from keyframe (a) to frame (b). The decoder
189 * decodes but clips all before media_time 1.
191 * After finishing a segment, we push out a new SEGMENT event with the clipping
192 * boundaries of the new data.
194 * This is a good usecase for the GStreamer accumulated SEGMENT events.
197 struct _QtDemuxSegment
199 /* global time and duration, all gst time */
201 GstClockTime stop_time;
202 GstClockTime duration;
203 /* media time of trak, all gst time */
204 GstClockTime media_start;
205 GstClockTime media_stop;
207 /* Media start time in trak timescale units */
208 guint32 trak_media_start;
211 #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
213 /* Used with fragmented MP4 files (mfra atom) */
218 } QtDemuxRandomAccessEntry;
220 struct _QtDemuxStream
231 gboolean new_stream; /* signals that a stream_start is required */
232 gboolean on_keyframe; /* if this stream last pushed buffer was a
233 * keyframe. This is important to identify
234 * where to stop pushing buffers after a
235 * segment stop time */
237 /* if the stream has a redirect URI in its headers, we store it here */
244 guint64 duration; /* in timescale */
248 gchar lang_id[4]; /* ISO 639-2T language code */
252 QtDemuxSample *samples;
253 gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */
254 guint32 first_duration; /* duration in timescale of first sample, used for figuring out
255 the framerate, in timescale units */
256 guint32 offset_in_sample;
257 guint32 max_buffer_size;
259 /* if we use chunks or samples */
271 /* Numerator/denominator framerate */
274 guint16 bits_per_sample;
275 guint16 color_table_id;
276 GstMemory *rgb8_palette;
281 guint samples_per_packet;
282 guint samples_per_frame;
283 guint bytes_per_packet;
284 guint bytes_per_sample;
285 guint bytes_per_frame;
289 gboolean use_allocator;
290 GstAllocator *allocator;
291 GstAllocationParams params;
293 /* when a discontinuity is pending */
296 /* list of buffers to push first */
299 /* if we need to clip this buffer. This is only needed for uncompressed
303 /* buffer needs some custom processing, e.g. subtitles */
304 gboolean need_process;
306 /* current position */
307 guint32 segment_index;
308 guint32 sample_index;
309 GstClockTime time_position; /* in gst time */
310 guint64 accumulated_base;
312 /* the Gst segment we are processing out, used for clipping */
314 guint32 segment_seqnum; /* segment event seqnum obtained from seek */
316 /* quicktime segments */
318 QtDemuxSegment *segments;
319 gboolean dummy_segment;
324 GstTagList *pending_tags;
325 gboolean send_global_tags;
327 GstEvent *pending_event;
337 gboolean chunks_are_samples; /* TRUE means treat chunks as samples */
341 GstByteReader co_chunk;
343 guint32 current_chunk;
345 guint32 samples_per_chunk;
346 guint32 stco_sample_index;
348 guint32 sample_size; /* 0 means variable sizes are stored in stsz */
351 guint32 n_samples_per_chunk;
352 guint32 stsc_chunk_index;
353 guint32 stsc_sample_index;
354 guint64 chunk_offset;
357 guint32 stts_samples;
358 guint32 n_sample_times;
359 guint32 stts_sample_index;
361 guint32 stts_duration;
363 gboolean stss_present;
364 guint32 n_sample_syncs;
367 gboolean stps_present;
368 guint32 n_sample_partial_syncs;
370 QtDemuxRandomAccessEntry *ra_entries;
373 const QtDemuxRandomAccessEntry *pending_seek;
376 gboolean ctts_present;
377 guint32 n_composition_times;
379 guint32 ctts_sample_index;
387 gboolean parsed_trex;
388 guint32 def_sample_duration;
389 guint32 def_sample_size;
390 guint32 def_sample_flags;
394 /* stereoscopic video streams */
395 GstVideoMultiviewMode multiview_mode;
396 GstVideoMultiviewFlags multiview_flags;
398 /* protected streams */
400 guint32 protection_scheme_type;
401 guint32 protection_scheme_version;
402 gpointer protection_scheme_info; /* specific to the protection scheme */
403 GQueue protection_scheme_event_queue;
406 /* Contains properties and cryptographic info for a set of samples from a
407 * track protected using Common Encryption (cenc) */
408 struct _QtDemuxCencSampleSetInfo
410 GstStructure *default_properties;
412 /* @crypto_info holds one GstStructure per sample */
413 GPtrArray *crypto_info;
418 QTDEMUX_STATE_INITIAL, /* Initial state (haven't got the header yet) */
419 QTDEMUX_STATE_HEADER, /* Parsing the header */
420 QTDEMUX_STATE_MOVIE, /* Parsing/Playing the media data */
421 QTDEMUX_STATE_BUFFER_MDAT /* Buffering the mdat atom */
424 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
425 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
426 guint32 fourcc, GstByteReader * parser);
427 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
428 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
429 guint32 fourcc, GstByteReader * parser);
431 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
433 static GstStaticPadTemplate gst_qtdemux_sink_template =
434 GST_STATIC_PAD_TEMPLATE ("sink",
437 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
441 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
442 GST_STATIC_PAD_TEMPLATE ("video_%u",
445 GST_STATIC_CAPS_ANY);
447 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
448 GST_STATIC_PAD_TEMPLATE ("audio_%u",
451 GST_STATIC_CAPS_ANY);
453 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
454 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
457 GST_STATIC_CAPS_ANY);
459 #define gst_qtdemux_parent_class parent_class
460 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
462 static void gst_qtdemux_dispose (GObject * object);
465 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
466 GstClockTime media_time);
468 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
469 QtDemuxStream * str, gint64 media_offset);
472 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
473 static GstIndex *gst_qtdemux_get_index (GstElement * element);
475 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
476 GstStateChange transition);
477 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
478 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
479 GstObject * parent, GstPadMode mode, gboolean active);
481 static void gst_qtdemux_loop (GstPad * pad);
482 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
484 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
486 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
487 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
488 QtDemuxStream * stream);
489 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
492 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
493 const guint8 * buffer, guint length);
494 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
495 const guint8 * buffer, guint length);
496 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
497 static void qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist,
500 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
501 QtDemuxStream * stream, GNode * esds, GstTagList * list);
502 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
503 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
504 gchar ** codec_name);
505 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
506 QtDemuxStream * stream, guint32 fourcc, const guint8 * data, int len,
507 gchar ** codec_name);
508 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux,
509 QtDemuxStream * stream, guint32 fourcc, const guint8 * data,
510 gchar ** codec_name);
511 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
512 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
513 gchar ** codec_name);
515 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
516 QtDemuxStream * stream, guint32 n);
517 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
518 static void gst_qtdemux_stream_free (GstQTDemux * qtdemux,
519 QtDemuxStream * stream);
520 static void gst_qtdemux_stream_clear (GstQTDemux * qtdemux,
521 QtDemuxStream * stream);
522 static void gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int index);
523 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
524 static void qtdemux_do_allocation (GstQTDemux * qtdemux,
525 QtDemuxStream * stream);
527 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
528 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
530 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
534 gst_qtdemux_class_init (GstQTDemuxClass * klass)
536 GObjectClass *gobject_class;
537 GstElementClass *gstelement_class;
539 gobject_class = (GObjectClass *) klass;
540 gstelement_class = (GstElementClass *) klass;
542 parent_class = g_type_class_peek_parent (klass);
544 gobject_class->dispose = gst_qtdemux_dispose;
546 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
548 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
549 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
552 gst_tag_register_musicbrainz_tags ();
554 gst_element_class_add_pad_template (gstelement_class,
555 gst_static_pad_template_get (&gst_qtdemux_sink_template));
556 gst_element_class_add_pad_template (gstelement_class,
557 gst_static_pad_template_get (&gst_qtdemux_videosrc_template));
558 gst_element_class_add_pad_template (gstelement_class,
559 gst_static_pad_template_get (&gst_qtdemux_audiosrc_template));
560 gst_element_class_add_pad_template (gstelement_class,
561 gst_static_pad_template_get (&gst_qtdemux_subsrc_template));
562 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
564 "Demultiplex a QuickTime file into audio and video streams",
565 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
567 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
572 gst_qtdemux_init (GstQTDemux * qtdemux)
575 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
576 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
577 gst_pad_set_activatemode_function (qtdemux->sinkpad,
578 qtdemux_sink_activate_mode);
579 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
580 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
581 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
583 qtdemux->state = QTDEMUX_STATE_INITIAL;
584 qtdemux->pullbased = FALSE;
585 qtdemux->posted_redirect = FALSE;
586 qtdemux->pending_configure = FALSE;
587 qtdemux->neededbytes = 16;
589 qtdemux->adapter = gst_adapter_new ();
591 qtdemux->first_mdat = -1;
592 qtdemux->got_moov = FALSE;
593 qtdemux->mdatoffset = -1;
594 qtdemux->mdatbuffer = NULL;
595 qtdemux->restoredata_buffer = NULL;
596 qtdemux->restoredata_offset = -1;
597 qtdemux->fragment_start = -1;
598 qtdemux->fragment_start_offset = -1;
599 qtdemux->media_caps = NULL;
600 qtdemux->exposed = FALSE;
601 qtdemux->mss_mode = FALSE;
602 qtdemux->pending_newsegment = NULL;
603 qtdemux->upstream_format_is_time = FALSE;
604 qtdemux->have_group_id = FALSE;
605 qtdemux->group_id = G_MAXUINT;
606 qtdemux->cenc_aux_info_offset = 0;
607 qtdemux->cenc_aux_info_sizes = NULL;
608 qtdemux->cenc_aux_sample_count = 0;
609 qtdemux->protection_system_ids = NULL;
610 g_queue_init (&qtdemux->protection_event_queue);
611 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
612 qtdemux->flowcombiner = gst_flow_combiner_new ();
614 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
618 gst_qtdemux_dispose (GObject * object)
620 GstQTDemux *qtdemux = GST_QTDEMUX (object);
622 if (qtdemux->adapter) {
623 g_object_unref (G_OBJECT (qtdemux->adapter));
624 qtdemux->adapter = NULL;
626 gst_flow_combiner_free (qtdemux->flowcombiner);
627 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
629 g_queue_clear (&qtdemux->protection_event_queue);
631 g_free (qtdemux->cenc_aux_info_sizes);
632 qtdemux->cenc_aux_info_sizes = NULL;
634 G_OBJECT_CLASS (parent_class)->dispose (object);
638 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
640 if (qtdemux->posted_redirect) {
641 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
642 (_("This file contains no playable streams.")),
643 ("no known streams found, a redirect message has been posted"));
645 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
646 (_("This file contains no playable streams.")),
647 ("no known streams found"));
652 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
654 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
655 mem, size, 0, size, mem, free_func);
659 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
666 if (G_UNLIKELY (size == 0)) {
668 GstBuffer *tmp = NULL;
670 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
671 if (ret != GST_FLOW_OK)
674 gst_buffer_map (tmp, &map, GST_MAP_READ);
675 size = QT_UINT32 (map.data);
676 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
678 gst_buffer_unmap (tmp, &map);
679 gst_buffer_unref (tmp);
682 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
683 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
684 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
685 /* we're pulling header but already got most interesting bits,
686 * so never mind the rest (e.g. tags) (that much) */
687 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
691 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
692 (_("This file is invalid and cannot be played.")),
693 ("atom has bogus size %" G_GUINT64_FORMAT, size));
694 return GST_FLOW_ERROR;
698 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
700 if (G_UNLIKELY (flow != GST_FLOW_OK))
703 bsize = gst_buffer_get_size (*buf);
704 /* Catch short reads - we don't want any partial atoms */
705 if (G_UNLIKELY (bsize < size)) {
706 GST_WARNING_OBJECT (qtdemux,
707 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
708 gst_buffer_unref (*buf);
718 gst_qtdemux_src_convert (GstPad * pad, GstFormat src_format, gint64 src_value,
719 GstFormat dest_format, gint64 * dest_value)
722 QtDemuxStream *stream = gst_pad_get_element_private (pad);
723 GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
726 if (stream->subtype != FOURCC_vide) {
731 switch (src_format) {
732 case GST_FORMAT_TIME:
733 switch (dest_format) {
734 case GST_FORMAT_BYTES:{
735 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
739 *dest_value = stream->samples[index].offset;
741 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
742 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
743 GST_TIME_ARGS (src_value), *dest_value);
751 case GST_FORMAT_BYTES:
752 switch (dest_format) {
753 case GST_FORMAT_TIME:{
755 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
762 QTSTREAMTIME_TO_GSTTIME (stream,
763 stream->samples[index].timestamp);
764 GST_DEBUG_OBJECT (qtdemux,
765 "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
766 GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
779 gst_object_unref (qtdemux);
786 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
790 *duration = GST_CLOCK_TIME_NONE;
792 if (qtdemux->duration != 0) {
793 if (qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
794 *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
801 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
804 gboolean res = FALSE;
805 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
807 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
809 switch (GST_QUERY_TYPE (query)) {
810 case GST_QUERY_POSITION:{
813 gst_query_parse_position (query, &fmt, NULL);
814 if (fmt == GST_FORMAT_TIME
815 && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
816 gst_query_set_position (query, GST_FORMAT_TIME,
817 qtdemux->segment.position);
822 case GST_QUERY_DURATION:{
825 gst_query_parse_duration (query, &fmt, NULL);
826 if (fmt == GST_FORMAT_TIME) {
827 /* First try to query upstream */
828 res = gst_pad_query_default (pad, parent, query);
831 if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
832 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
839 case GST_QUERY_CONVERT:{
840 GstFormat src_fmt, dest_fmt;
841 gint64 src_value, dest_value = 0;
843 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
845 res = gst_qtdemux_src_convert (pad,
846 src_fmt, src_value, dest_fmt, &dest_value);
848 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
853 case GST_QUERY_FORMATS:
854 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
857 case GST_QUERY_SEEKING:{
861 /* try upstream first */
862 res = gst_pad_query_default (pad, parent, query);
865 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
866 if (fmt == GST_FORMAT_TIME) {
867 GstClockTime duration = GST_CLOCK_TIME_NONE;
869 gst_qtdemux_get_duration (qtdemux, &duration);
871 if (!qtdemux->pullbased) {
874 /* we might be able with help from upstream */
876 q = gst_query_new_seeking (GST_FORMAT_BYTES);
877 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
878 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
879 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
883 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
889 case GST_QUERY_SEGMENT:
894 format = qtdemux->segment.format;
897 gst_segment_to_stream_time (&qtdemux->segment, format,
898 qtdemux->segment.start);
899 if ((stop = qtdemux->segment.stop) == -1)
900 stop = qtdemux->segment.duration;
902 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
904 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
909 res = gst_pad_query_default (pad, parent, query);
917 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
919 if (G_LIKELY (stream->pad)) {
920 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
921 GST_DEBUG_PAD_NAME (stream->pad));
923 if (G_UNLIKELY (stream->pending_tags)) {
924 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
925 stream->pending_tags);
926 gst_pad_push_event (stream->pad,
927 gst_event_new_tag (stream->pending_tags));
928 stream->pending_tags = NULL;
931 if (G_UNLIKELY (stream->send_global_tags && qtdemux->tag_list)) {
932 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
934 gst_pad_push_event (stream->pad,
935 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
936 stream->send_global_tags = FALSE;
941 /* push event on all source pads; takes ownership of the event */
943 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
946 gboolean has_valid_stream = FALSE;
947 GstEventType etype = GST_EVENT_TYPE (event);
949 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
950 GST_EVENT_TYPE_NAME (event));
952 for (n = 0; n < qtdemux->n_streams; n++) {
954 QtDemuxStream *stream = qtdemux->streams[n];
955 GST_DEBUG_OBJECT (qtdemux, "pushing on pad %i", n);
957 if ((pad = stream->pad)) {
958 has_valid_stream = TRUE;
960 if (etype == GST_EVENT_EOS) {
961 /* let's not send twice */
962 if (stream->sent_eos)
964 stream->sent_eos = TRUE;
967 gst_pad_push_event (pad, gst_event_ref (event));
971 gst_event_unref (event);
973 /* if it is EOS and there are no pads, post an error */
974 if (!has_valid_stream && etype == GST_EVENT_EOS) {
975 gst_qtdemux_post_no_playable_stream_error (qtdemux);
979 /* push a pending newsegment event, if any from the streaming thread */
981 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
983 if (qtdemux->pending_newsegment) {
984 gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
985 qtdemux->pending_newsegment = NULL;
995 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
997 if ((gint64) s1->timestamp + s1->pts_offset > *media_time)
999 if ((gint64) s1->timestamp + s1->pts_offset == *media_time)
1005 /* find the index of the sample that includes the data for @media_time using a
1006 * binary search. Only to be called in optimized cases of linear search below.
1008 * Returns the index of the sample.
1011 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
1014 QtDemuxSample *result;
1017 /* convert media_time to mov format */
1019 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1021 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
1022 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
1023 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
1025 if (G_LIKELY (result))
1026 index = result - str->samples;
1035 /* find the index of the sample that includes the data for @media_offset using a
1038 * Returns the index of the sample.
1041 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
1042 QtDemuxStream * str, gint64 media_offset)
1044 QtDemuxSample *result = str->samples;
1047 if (result == NULL || str->n_samples == 0)
1050 if (media_offset == result->offset)
1054 while (index < str->n_samples - 1) {
1055 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1058 if (media_offset < result->offset)
1069 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1074 /* find the index of the sample that includes the data for @media_time using a
1075 * linear search, and keeping in mind that not all samples may have been parsed
1076 * yet. If possible, it will delegate to binary search.
1078 * Returns the index of the sample.
1081 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
1082 GstClockTime media_time)
1086 QtDemuxSample *sample;
1088 /* convert media_time to mov format */
1090 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1092 sample = str->samples;
1093 if (mov_time == sample->timestamp + sample->pts_offset)
1096 /* use faster search if requested time in already parsed range */
1097 sample = str->samples + str->stbl_index;
1098 if (str->stbl_index >= 0 &&
1099 mov_time <= (sample->timestamp + sample->pts_offset))
1100 return gst_qtdemux_find_index (qtdemux, str, media_time);
1102 while (index < str->n_samples - 1) {
1103 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1106 sample = str->samples + index + 1;
1107 if (mov_time < (sample->timestamp + sample->pts_offset))
1117 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1122 /* find the index of the keyframe needed to decode the sample at @index
1125 * Returns the index of the keyframe.
1128 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1131 guint32 new_index = index;
1133 if (index >= str->n_samples) {
1134 new_index = str->n_samples;
1138 /* all keyframes, return index */
1139 if (str->all_keyframe) {
1144 /* else go back until we have a keyframe */
1146 if (str->samples[new_index].keyframe)
1156 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index before index %u "
1157 "gave %u", index, new_index);
1162 /* find the segment for @time_position for @stream
1164 * Returns the index of the segment containing @time_position.
1165 * Returns the last segment and sets the @eos variable to TRUE
1166 * if the time is beyond the end. @eos may be NULL
1169 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1170 GstClockTime time_position)
1175 GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1176 GST_TIME_ARGS (time_position));
1179 for (i = 0; i < stream->n_segments; i++) {
1180 QtDemuxSegment *segment = &stream->segments[i];
1182 GST_LOG_OBJECT (stream->pad,
1183 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1184 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1186 /* For the last segment we include stop_time in the last segment */
1187 if (i < stream->n_segments - 1) {
1188 if (segment->time <= time_position && time_position < segment->stop_time) {
1189 GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1194 /* Last segment always matches */
1202 /* move the stream @str to the sample position @index.
1204 * Updates @str->sample_index and marks discontinuity if needed.
1207 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1210 /* no change needed */
1211 if (index == str->sample_index)
1214 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1217 /* position changed, we have a discont */
1218 str->sample_index = index;
1219 str->offset_in_sample = 0;
1220 /* Each time we move in the stream we store the position where we are
1222 str->from_sample = index;
1223 str->discont = TRUE;
1227 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1228 gboolean use_sparse, gint64 * key_time, gint64 * key_offset)
1231 gint64 min_byte_offset = -1;
1234 min_offset = desired_time;
1236 /* for each stream, find the index of the sample in the segment
1237 * and move back to the previous keyframe. */
1238 for (n = 0; n < qtdemux->n_streams; n++) {
1240 guint32 index, kindex;
1242 GstClockTime media_start;
1243 GstClockTime media_time;
1244 GstClockTime seg_time;
1245 QtDemuxSegment *seg;
1246 gboolean empty_segment = FALSE;
1248 str = qtdemux->streams[n];
1250 if (str->sparse && !use_sparse)
1253 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1254 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1256 /* get segment and time in the segment */
1257 seg = &str->segments[seg_idx];
1258 seg_time = desired_time - seg->time;
1260 while (QTSEGMENT_IS_EMPTY (seg)) {
1262 empty_segment = TRUE;
1263 GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1266 if (seg_idx == str->n_segments)
1268 seg = &str->segments[seg_idx];
1271 if (seg_idx == str->n_segments) {
1272 /* FIXME track shouldn't have the last segment as empty, but if it
1273 * happens we better handle it */
1277 /* get the media time in the segment */
1278 media_start = seg->media_start + seg_time;
1280 /* get the index of the sample with media time */
1281 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1282 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1283 " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1284 GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1287 if (!empty_segment) {
1288 /* find previous keyframe */
1289 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index);
1291 /* if the keyframe is at a different position, we need to update the
1292 * requested seek time */
1293 if (index != kindex) {
1296 /* get timestamp of keyframe */
1297 media_time = QTSAMPLE_DTS (str, &str->samples[kindex]);
1298 GST_DEBUG_OBJECT (qtdemux,
1299 "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1300 G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1301 str->samples[kindex].offset);
1303 /* keyframes in the segment get a chance to change the
1304 * desired_offset. keyframes out of the segment are
1306 if (media_time >= seg->media_start) {
1307 GstClockTime seg_time;
1309 /* this keyframe is inside the segment, convert back to
1311 seg_time = (media_time - seg->media_start) + seg->time;
1312 if (seg_time < min_offset)
1313 min_offset = seg_time;
1318 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1319 min_byte_offset = str->samples[index].offset;
1323 *key_time = min_offset;
1325 *key_offset = min_byte_offset;
1329 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1330 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1334 g_return_val_if_fail (format != NULL, FALSE);
1335 g_return_val_if_fail (cur != NULL, FALSE);
1336 g_return_val_if_fail (stop != NULL, FALSE);
1338 if (*format == GST_FORMAT_TIME)
1342 if (cur_type != GST_SEEK_TYPE_NONE)
1343 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1344 if (res && stop_type != GST_SEEK_TYPE_NONE)
1345 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1348 *format = GST_FORMAT_TIME;
1353 /* perform seek in push based mode:
1354 find BYTE position to move to based on time and delegate to upstream
1357 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1362 GstSeekType cur_type, stop_type;
1363 gint64 cur, stop, key_cur;
1366 gint64 original_stop;
1369 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1371 gst_event_parse_seek (event, &rate, &format, &flags,
1372 &cur_type, &cur, &stop_type, &stop);
1373 seqnum = gst_event_get_seqnum (event);
1375 /* only forward streaming and seeking is possible */
1377 goto unsupported_seek;
1379 /* convert to TIME if needed and possible */
1380 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1384 /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1385 * the original stop position to use when upstream pushes the new segment
1387 original_stop = stop;
1390 /* find reasonable corresponding BYTE position,
1391 * also try to mind about keyframes, since we can not go back a bit for them
1393 gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, &key_cur, &byte_cur);
1398 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1399 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1402 GST_OBJECT_LOCK (qtdemux);
1403 qtdemux->seek_offset = byte_cur;
1404 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1405 qtdemux->push_seek_start = cur;
1407 qtdemux->push_seek_start = key_cur;
1410 if (stop_type == GST_SEEK_TYPE_NONE) {
1411 qtdemux->push_seek_stop = qtdemux->segment.stop;
1413 qtdemux->push_seek_stop = original_stop;
1415 GST_OBJECT_UNLOCK (qtdemux);
1417 /* BYTE seek event */
1418 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1420 gst_event_set_seqnum (event, seqnum);
1421 res = gst_pad_push_event (qtdemux->sinkpad, event);
1428 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1434 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1439 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1444 /* perform the seek.
1446 * We set all segment_indexes in the streams to unknown and
1447 * adjust the time_position to the desired position. this is enough
1448 * to trigger a segment switch in the streaming thread to start
1449 * streaming from the desired position.
1451 * Keyframe seeking is a little more complicated when dealing with
1452 * segments. Ideally we want to move to the previous keyframe in
1453 * the segment but there might not be a keyframe in the segment. In
1454 * fact, none of the segments could contain a keyframe. We take a
1455 * practical approach: seek to the previous keyframe in the segment,
1456 * if there is none, seek to the beginning of the segment.
1458 * Called with STREAM_LOCK
1461 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1462 guint32 seqnum, GstSeekFlags flags)
1464 gint64 desired_offset;
1467 desired_offset = segment->position;
1469 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1470 GST_TIME_ARGS (desired_offset));
1472 /* may not have enough fragmented info to do this adjustment,
1473 * and we can't scan (and probably should not) at this time with
1474 * possibly flushing upstream */
1475 if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1478 gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, &min_offset, NULL);
1479 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1480 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1481 desired_offset = min_offset;
1484 /* and set all streams to the final position */
1485 gst_flow_combiner_reset (qtdemux->flowcombiner);
1486 for (n = 0; n < qtdemux->n_streams; n++) {
1487 QtDemuxStream *stream = qtdemux->streams[n];
1489 stream->time_position = desired_offset;
1490 stream->accumulated_base = 0;
1491 stream->sample_index = -1;
1492 stream->offset_in_sample = 0;
1493 stream->segment_index = -1;
1494 stream->sent_eos = FALSE;
1495 stream->segment_seqnum = seqnum;
1497 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1498 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1500 segment->position = desired_offset;
1501 segment->time = desired_offset;
1502 if (segment->rate >= 0) {
1503 segment->start = desired_offset;
1505 /* we stop at the end */
1506 if (segment->stop == -1)
1507 segment->stop = segment->duration;
1509 segment->stop = desired_offset;
1512 if (qtdemux->fragmented)
1513 qtdemux->fragmented_seek_pending = TRUE;
1518 /* do a seek in pull based mode */
1520 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1525 GstSeekType cur_type, stop_type;
1529 GstSegment seeksegment;
1531 GstEvent *flush_event;
1534 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1536 gst_event_parse_seek (event, &rate, &format, &flags,
1537 &cur_type, &cur, &stop_type, &stop);
1538 seqnum = gst_event_get_seqnum (event);
1540 /* we have to have a format as the segment format. Try to convert
1542 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1546 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1548 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1552 flush = flags & GST_SEEK_FLAG_FLUSH;
1554 /* stop streaming, either by flushing or by pausing the task */
1556 flush_event = gst_event_new_flush_start ();
1558 gst_event_set_seqnum (flush_event, seqnum);
1559 /* unlock upstream pull_range */
1560 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1561 /* make sure out loop function exits */
1562 gst_qtdemux_push_event (qtdemux, flush_event);
1564 /* non flushing seek, pause the task */
1565 gst_pad_pause_task (qtdemux->sinkpad);
1568 /* wait for streaming to finish */
1569 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1571 /* copy segment, we need this because we still need the old
1572 * segment when we close the current segment. */
1573 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1576 /* configure the segment with the seek variables */
1577 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1578 gst_segment_do_seek (&seeksegment, rate, format, flags,
1579 cur_type, cur, stop_type, stop, &update);
1582 /* now do the seek, this actually never returns FALSE */
1583 gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1585 /* prepare for streaming again */
1587 flush_event = gst_event_new_flush_stop (TRUE);
1589 gst_event_set_seqnum (flush_event, seqnum);
1591 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1592 gst_qtdemux_push_event (qtdemux, flush_event);
1595 /* commit the new segment */
1596 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1598 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1599 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1600 qtdemux->segment.format, qtdemux->segment.position);
1602 gst_message_set_seqnum (msg, seqnum);
1603 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1606 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1607 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1608 qtdemux->sinkpad, NULL);
1610 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1617 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1623 qtdemux_ensure_index (GstQTDemux * qtdemux)
1627 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1629 /* Build complete index */
1630 for (i = 0; i < qtdemux->n_streams; i++) {
1631 QtDemuxStream *stream = qtdemux->streams[i];
1633 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1641 GST_LOG_OBJECT (qtdemux,
1642 "Building complete index of stream %u for seeking failed!", i);
1648 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1651 gboolean res = TRUE;
1652 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1654 switch (GST_EVENT_TYPE (event)) {
1655 case GST_EVENT_SEEK:
1657 #ifndef GST_DISABLE_GST_DEBUG
1658 GstClockTime ts = gst_util_get_timestamp ();
1661 if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1662 /* seek should be handled by upstream, we might need to re-download fragments */
1663 GST_DEBUG_OBJECT (qtdemux,
1664 "let upstream handle seek for fragmented playback");
1668 /* Build complete index for seeking;
1669 * if not a fragmented file at least */
1670 if (!qtdemux->fragmented)
1671 if (!qtdemux_ensure_index (qtdemux))
1673 #ifndef GST_DISABLE_GST_DEBUG
1674 ts = gst_util_get_timestamp () - ts;
1675 GST_INFO_OBJECT (qtdemux,
1676 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1679 if (qtdemux->pullbased) {
1680 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1681 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1682 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1684 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams
1685 && !qtdemux->fragmented) {
1686 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1688 GST_DEBUG_OBJECT (qtdemux,
1689 "ignoring seek in push mode in current state");
1692 gst_event_unref (event);
1695 case GST_EVENT_NAVIGATION:
1697 gst_event_unref (event);
1701 res = gst_pad_event_default (pad, parent, event);
1711 GST_ERROR_OBJECT (qtdemux, "Index failed");
1712 gst_event_unref (event);
1718 /* stream/index return sample that is min/max w.r.t. byte position,
1719 * time is min/max w.r.t. time of samples,
1720 * the latter need not be time of the former sample */
1722 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1723 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1726 gint64 time, min_time;
1727 QtDemuxStream *stream;
1733 for (n = 0; n < qtdemux->n_streams; ++n) {
1736 gboolean set_sample;
1738 str = qtdemux->streams[n];
1745 i = str->n_samples - 1;
1749 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1750 if (str->samples[i].size == 0)
1753 if (fw && (str->samples[i].offset < byte_pos))
1756 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1759 /* move stream to first available sample */
1761 gst_qtdemux_move_stream (qtdemux, str, i);
1765 /* avoid index from sparse streams since they might be far away */
1767 /* determine min/max time */
1768 time = QTSAMPLE_PTS (str, &str->samples[i]);
1769 if (min_time == -1 || (!fw && time > min_time) ||
1770 (fw && time < min_time)) {
1774 /* determine stream with leading sample, to get its position */
1776 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1777 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1785 /* no sample for this stream, mark eos */
1787 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1798 static QtDemuxStream *
1799 _create_stream (void)
1801 QtDemuxStream *stream;
1803 stream = g_new0 (QtDemuxStream, 1);
1804 /* new streams always need a discont */
1805 stream->discont = TRUE;
1806 /* we enable clipping for raw audio/video streams */
1807 stream->need_clip = FALSE;
1808 stream->need_process = FALSE;
1809 stream->segment_index = -1;
1810 stream->time_position = 0;
1811 stream->sample_index = -1;
1812 stream->offset_in_sample = 0;
1813 stream->new_stream = TRUE;
1814 stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1815 stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1816 stream->protected = FALSE;
1817 stream->protection_scheme_type = 0;
1818 stream->protection_scheme_version = 0;
1819 stream->protection_scheme_info = NULL;
1820 g_queue_init (&stream->protection_scheme_event_queue);
1825 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1827 GstStructure *structure;
1828 const gchar *variant;
1829 const GstCaps *mediacaps = NULL;
1831 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1833 structure = gst_caps_get_structure (caps, 0);
1834 variant = gst_structure_get_string (structure, "variant");
1836 if (variant && strcmp (variant, "mss-fragmented") == 0) {
1837 QtDemuxStream *stream;
1838 const GValue *value;
1840 demux->fragmented = TRUE;
1841 demux->mss_mode = TRUE;
1843 if (demux->n_streams > 1) {
1844 /* can't do this, we can only renegotiate for another mss format */
1848 value = gst_structure_get_value (structure, "media-caps");
1851 const GValue *timescale_v;
1853 /* TODO update when stream changes during playback */
1855 if (demux->n_streams == 0) {
1856 stream = _create_stream ();
1857 demux->streams[demux->n_streams] = stream;
1858 demux->n_streams = 1;
1860 stream = demux->streams[0];
1863 timescale_v = gst_structure_get_value (structure, "timescale");
1865 stream->timescale = g_value_get_uint64 (timescale_v);
1867 /* default mss timescale */
1868 stream->timescale = 10000000;
1870 demux->timescale = stream->timescale;
1872 mediacaps = gst_value_get_caps (value);
1873 if (!stream->caps || !gst_caps_is_equal_fixed (mediacaps, stream->caps)) {
1874 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1876 stream->new_caps = TRUE;
1878 gst_caps_replace (&stream->caps, (GstCaps *) mediacaps);
1879 structure = gst_caps_get_structure (mediacaps, 0);
1880 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
1881 stream->subtype = FOURCC_vide;
1883 gst_structure_get_int (structure, "width", &stream->width);
1884 gst_structure_get_int (structure, "height", &stream->height);
1885 gst_structure_get_fraction (structure, "framerate", &stream->fps_n,
1887 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
1889 stream->subtype = FOURCC_soun;
1890 gst_structure_get_int (structure, "channels", &stream->n_channels);
1891 gst_structure_get_int (structure, "rate", &rate);
1892 stream->rate = rate;
1895 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
1897 demux->mss_mode = FALSE;
1904 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
1908 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
1909 gst_pad_stop_task (qtdemux->sinkpad);
1911 if (hard || qtdemux->upstream_format_is_time) {
1912 qtdemux->state = QTDEMUX_STATE_INITIAL;
1913 qtdemux->neededbytes = 16;
1914 qtdemux->todrop = 0;
1915 qtdemux->pullbased = FALSE;
1916 qtdemux->posted_redirect = FALSE;
1917 qtdemux->first_mdat = -1;
1918 qtdemux->header_size = 0;
1919 qtdemux->mdatoffset = -1;
1920 qtdemux->restoredata_offset = -1;
1921 if (qtdemux->mdatbuffer)
1922 gst_buffer_unref (qtdemux->mdatbuffer);
1923 if (qtdemux->restoredata_buffer)
1924 gst_buffer_unref (qtdemux->restoredata_buffer);
1925 qtdemux->mdatbuffer = NULL;
1926 qtdemux->restoredata_buffer = NULL;
1927 qtdemux->mdatleft = 0;
1928 if (qtdemux->comp_brands)
1929 gst_buffer_unref (qtdemux->comp_brands);
1930 qtdemux->comp_brands = NULL;
1931 qtdemux->last_moov_offset = -1;
1932 if (qtdemux->moov_node)
1933 g_node_destroy (qtdemux->moov_node);
1934 qtdemux->moov_node = NULL;
1935 qtdemux->moov_node_compressed = NULL;
1936 if (qtdemux->tag_list)
1937 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
1938 qtdemux->tag_list = NULL;
1940 if (qtdemux->element_index)
1941 gst_object_unref (qtdemux->element_index);
1942 qtdemux->element_index = NULL;
1944 qtdemux->major_brand = 0;
1945 if (qtdemux->pending_newsegment)
1946 gst_event_unref (qtdemux->pending_newsegment);
1947 qtdemux->pending_newsegment = NULL;
1948 qtdemux->upstream_format_is_time = FALSE;
1949 qtdemux->upstream_seekable = FALSE;
1950 qtdemux->upstream_size = 0;
1952 qtdemux->fragment_start = -1;
1953 qtdemux->fragment_start_offset = -1;
1954 qtdemux->duration = 0;
1955 qtdemux->moof_offset = 0;
1956 qtdemux->chapters_track_id = 0;
1957 qtdemux->have_group_id = FALSE;
1958 qtdemux->group_id = G_MAXUINT;
1960 if (qtdemux->protection_system_ids) {
1961 g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
1962 qtdemux->protection_system_ids = NULL;
1964 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
1966 g_queue_clear (&qtdemux->protection_event_queue);
1968 qtdemux->offset = 0;
1969 gst_adapter_clear (qtdemux->adapter);
1970 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
1973 for (n = 0; n < qtdemux->n_streams; n++) {
1974 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
1975 qtdemux->streams[n] = NULL;
1977 qtdemux->n_streams = 0;
1978 qtdemux->n_video_streams = 0;
1979 qtdemux->n_audio_streams = 0;
1980 qtdemux->n_sub_streams = 0;
1981 qtdemux->exposed = FALSE;
1982 qtdemux->fragmented = FALSE;
1983 qtdemux->mss_mode = FALSE;
1984 gst_caps_replace (&qtdemux->media_caps, NULL);
1985 qtdemux->timescale = 0;
1986 qtdemux->got_moov = FALSE;
1987 qtdemux->pending_configure = FALSE;
1988 } else if (qtdemux->mss_mode) {
1989 gst_flow_combiner_reset (qtdemux->flowcombiner);
1990 for (n = 0; n < qtdemux->n_streams; n++)
1991 gst_qtdemux_stream_clear (qtdemux, qtdemux->streams[n]);
1993 gst_flow_combiner_reset (qtdemux->flowcombiner);
1994 for (n = 0; n < qtdemux->n_streams; n++) {
1995 qtdemux->streams[n]->sent_eos = FALSE;
1996 qtdemux->streams[n]->segment_seqnum = 0;
1997 qtdemux->streams[n]->time_position = 0;
1998 qtdemux->streams[n]->accumulated_base = 0;
2000 if (!qtdemux->pending_newsegment) {
2001 qtdemux->pending_newsegment = gst_event_new_segment (&qtdemux->segment);
2007 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2010 GstQTDemux *demux = GST_QTDEMUX (parent);
2011 gboolean res = TRUE;
2013 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2015 switch (GST_EVENT_TYPE (event)) {
2016 case GST_EVENT_SEGMENT:
2019 QtDemuxStream *stream;
2022 GstEvent *segment_event;
2024 /* some debug output */
2025 gst_event_copy_segment (event, &segment);
2026 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2029 if (segment.format == GST_FORMAT_TIME) {
2030 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
2031 gst_event_replace (&demux->pending_newsegment, event);
2032 demux->upstream_format_is_time = TRUE;
2034 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2035 "not in time format");
2037 /* chain will send initial newsegment after pads have been added */
2038 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
2039 GST_DEBUG_OBJECT (demux, "still starting, eating event");
2044 /* check if this matches a time seek we received previously
2045 * FIXME for backwards compatibility reasons we use the
2046 * seek_offset here to compare. In the future we might want to
2047 * change this to use the seqnum as it uniquely should identify
2048 * the segment that corresponds to the seek. */
2049 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2050 ", received segment offset %" G_GINT64_FORMAT,
2051 demux->seek_offset, segment.start);
2052 if (segment.format == GST_FORMAT_BYTES
2053 && demux->seek_offset == segment.start) {
2054 GST_OBJECT_LOCK (demux);
2055 offset = segment.start;
2057 segment.format = GST_FORMAT_TIME;
2058 segment.start = demux->push_seek_start;
2059 segment.stop = demux->push_seek_stop;
2060 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2061 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2062 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2063 GST_OBJECT_UNLOCK (demux);
2066 /* we only expect a BYTE segment, e.g. following a seek */
2067 if (segment.format == GST_FORMAT_BYTES) {
2068 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2069 offset = segment.start;
2071 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2072 NULL, (gint64 *) & segment.start);
2073 if ((gint64) segment.start < 0)
2076 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2077 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2078 NULL, (gint64 *) & segment.stop);
2079 /* keyframe seeking should already arrange for start >= stop,
2080 * but make sure in other rare cases */
2081 segment.stop = MAX (segment.stop, segment.start);
2083 } else if (segment.format == GST_FORMAT_TIME) {
2084 /* push all data on the adapter before starting this
2086 gst_qtdemux_process_adapter (demux, TRUE);
2088 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2092 /* accept upstream's notion of segment and distribute along */
2093 segment.format = GST_FORMAT_TIME;
2094 segment.position = segment.time = segment.start;
2095 segment.duration = demux->segment.duration;
2096 segment.base = gst_segment_to_running_time (&demux->segment,
2097 GST_FORMAT_TIME, demux->segment.position);
2099 gst_segment_copy_into (&segment, &demux->segment);
2100 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2101 segment_event = gst_event_new_segment (&segment);
2102 gst_event_set_seqnum (segment_event, gst_event_get_seqnum (event));
2103 gst_qtdemux_push_event (demux, segment_event);
2105 /* clear leftover in current segment, if any */
2106 gst_adapter_clear (demux->adapter);
2108 /* set up streaming thread */
2109 demux->offset = offset;
2110 if (demux->upstream_format_is_time) {
2111 GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2112 "set values to restart reading from a new atom");
2113 demux->neededbytes = 16;
2116 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2119 demux->todrop = stream->samples[idx].offset - offset;
2120 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2122 /* set up for EOS */
2123 demux->neededbytes = -1;
2128 gst_event_unref (event);
2132 case GST_EVENT_FLUSH_START:
2134 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2135 gst_event_unref (event);
2140 case GST_EVENT_FLUSH_STOP:
2144 dur = demux->segment.duration;
2145 gst_qtdemux_reset (demux, FALSE);
2146 demux->segment.duration = dur;
2148 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2149 gst_event_unref (event);
2155 /* If we are in push mode, and get an EOS before we've seen any streams,
2156 * then error out - we have nowhere to send the EOS */
2157 if (!demux->pullbased) {
2159 gboolean has_valid_stream = FALSE;
2160 for (i = 0; i < demux->n_streams; i++) {
2161 if (demux->streams[i]->pad != NULL) {
2162 has_valid_stream = TRUE;
2166 if (!has_valid_stream)
2167 gst_qtdemux_post_no_playable_stream_error (demux);
2169 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2170 (guint) gst_adapter_available (demux->adapter));
2171 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2177 case GST_EVENT_CAPS:{
2178 GstCaps *caps = NULL;
2180 gst_event_parse_caps (event, &caps);
2181 gst_qtdemux_setcaps (demux, caps);
2183 gst_event_unref (event);
2186 case GST_EVENT_PROTECTION:
2188 const gchar *system_id = NULL;
2190 gst_event_parse_protection (event, &system_id, NULL, NULL);
2191 GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2193 gst_qtdemux_append_protection_system_id (demux, system_id);
2194 /* save the event for later, for source pads that have not been created */
2195 g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2196 /* send it to all pads that already exist */
2197 gst_qtdemux_push_event (demux, event);
2205 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2213 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2215 GstQTDemux *demux = GST_QTDEMUX (element);
2217 GST_OBJECT_LOCK (demux);
2218 if (demux->element_index)
2219 gst_object_unref (demux->element_index);
2221 demux->element_index = gst_object_ref (index);
2223 demux->element_index = NULL;
2225 GST_OBJECT_UNLOCK (demux);
2226 /* object lock might be taken again */
2228 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2229 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2230 demux->element_index, demux->index_id);
2234 gst_qtdemux_get_index (GstElement * element)
2236 GstIndex *result = NULL;
2237 GstQTDemux *demux = GST_QTDEMUX (element);
2239 GST_OBJECT_LOCK (demux);
2240 if (demux->element_index)
2241 result = gst_object_ref (demux->element_index);
2242 GST_OBJECT_UNLOCK (demux);
2244 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2251 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2253 g_free ((gpointer) stream->stco.data);
2254 stream->stco.data = NULL;
2255 g_free ((gpointer) stream->stsz.data);
2256 stream->stsz.data = NULL;
2257 g_free ((gpointer) stream->stsc.data);
2258 stream->stsc.data = NULL;
2259 g_free ((gpointer) stream->stts.data);
2260 stream->stts.data = NULL;
2261 g_free ((gpointer) stream->stss.data);
2262 stream->stss.data = NULL;
2263 g_free ((gpointer) stream->stps.data);
2264 stream->stps.data = NULL;
2265 g_free ((gpointer) stream->ctts.data);
2266 stream->ctts.data = NULL;
2270 gst_qtdemux_stream_flush_segments_data (GstQTDemux * qtdemux,
2271 QtDemuxStream * stream)
2273 g_free (stream->segments);
2274 stream->segments = NULL;
2275 stream->segment_index = -1;
2276 stream->accumulated_base = 0;
2280 gst_qtdemux_stream_flush_samples_data (GstQTDemux * qtdemux,
2281 QtDemuxStream * stream)
2283 g_free (stream->samples);
2284 stream->samples = NULL;
2285 gst_qtdemux_stbl_free (stream);
2288 g_free (stream->ra_entries);
2289 stream->ra_entries = NULL;
2290 stream->n_ra_entries = 0;
2292 stream->sample_index = -1;
2293 stream->stbl_index = -1;
2294 stream->n_samples = 0;
2295 stream->time_position = 0;
2299 gst_qtdemux_stream_clear (GstQTDemux * qtdemux, QtDemuxStream * stream)
2301 if (stream->allocator)
2302 gst_object_unref (stream->allocator);
2303 while (stream->buffers) {
2304 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2305 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2307 if (stream->rgb8_palette) {
2308 gst_memory_unref (stream->rgb8_palette);
2309 stream->rgb8_palette = NULL;
2312 if (stream->pending_tags)
2313 gst_tag_list_unref (stream->pending_tags);
2314 stream->pending_tags = NULL;
2315 g_free (stream->redirect_uri);
2316 stream->redirect_uri = NULL;
2317 stream->sent_eos = FALSE;
2318 stream->sparse = FALSE;
2319 stream->protected = FALSE;
2320 if (stream->protection_scheme_info) {
2321 if (stream->protection_scheme_type == FOURCC_cenc) {
2322 QtDemuxCencSampleSetInfo *info =
2323 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2324 if (info->default_properties)
2325 gst_structure_free (info->default_properties);
2326 if (info->crypto_info)
2327 g_ptr_array_free (info->crypto_info, TRUE);
2329 g_free (stream->protection_scheme_info);
2330 stream->protection_scheme_info = NULL;
2332 stream->protection_scheme_type = 0;
2333 stream->protection_scheme_version = 0;
2334 g_queue_foreach (&stream->protection_scheme_event_queue,
2335 (GFunc) gst_event_unref, NULL);
2336 g_queue_clear (&stream->protection_scheme_event_queue);
2337 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
2338 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
2342 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
2344 gst_qtdemux_stream_clear (qtdemux, stream);
2346 gst_caps_unref (stream->caps);
2347 stream->caps = NULL;
2349 gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
2350 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, stream->pad);
2356 gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int i)
2358 g_assert (i >= 0 && i < qtdemux->n_streams && qtdemux->streams[i] != NULL);
2360 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[i]);
2361 qtdemux->streams[i] = qtdemux->streams[qtdemux->n_streams - 1];
2362 qtdemux->streams[qtdemux->n_streams - 1] = NULL;
2363 qtdemux->n_streams--;
2366 static GstStateChangeReturn
2367 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2369 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2370 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2372 switch (transition) {
2373 case GST_STATE_CHANGE_PAUSED_TO_READY:
2379 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2381 switch (transition) {
2382 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2383 gst_qtdemux_reset (qtdemux, TRUE);
2394 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2396 /* counts as header data */
2397 qtdemux->header_size += length;
2399 /* only consider at least a sufficiently complete ftyp atom */
2403 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2404 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2405 GST_FOURCC_ARGS (qtdemux->major_brand));
2406 if (qtdemux->comp_brands)
2407 gst_buffer_unref (qtdemux->comp_brands);
2408 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2409 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2414 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist,
2415 GstTagList * xmptaglist)
2417 /* Strip out bogus fields */
2419 if (gst_tag_list_get_scope (taglist) == GST_TAG_SCOPE_GLOBAL) {
2420 gst_tag_list_remove_tag (xmptaglist, GST_TAG_VIDEO_CODEC);
2421 gst_tag_list_remove_tag (xmptaglist, GST_TAG_AUDIO_CODEC);
2423 gst_tag_list_remove_tag (xmptaglist, GST_TAG_CONTAINER_FORMAT);
2426 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, xmptaglist);
2428 /* prioritize native tags using _KEEP mode */
2429 gst_tag_list_insert (taglist, xmptaglist, GST_TAG_MERGE_KEEP);
2430 gst_tag_list_unref (xmptaglist);
2435 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2437 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2438 0x97, 0xA9, 0x42, 0xE8,
2439 0x9C, 0x71, 0x99, 0x94,
2440 0x91, 0xE3, 0xAF, 0xAC
2442 static const guint8 playready_uuid[] = {
2443 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2444 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2448 /* counts as header data */
2449 qtdemux->header_size += length;
2451 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2453 if (length <= offset + 16) {
2454 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2458 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2460 GstTagList *taglist;
2462 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2463 length - offset - 16, NULL);
2464 taglist = gst_tag_list_from_xmp_buffer (buf);
2465 gst_buffer_unref (buf);
2467 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
2469 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
2471 const gunichar2 *s_utf16;
2474 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
2475 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
2476 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
2477 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
2481 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
2482 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
2485 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
2486 GST_READ_UINT32_LE (buffer + offset),
2487 GST_READ_UINT32_LE (buffer + offset + 4),
2488 GST_READ_UINT32_LE (buffer + offset + 8),
2489 GST_READ_UINT32_LE (buffer + offset + 12));
2494 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2496 GstSidxParser sidx_parser;
2497 GstIsoffParserResult res;
2500 gst_isoff_qt_sidx_parser_init (&sidx_parser);
2503 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
2505 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
2506 if (res == GST_ISOFF_QT_PARSER_DONE) {
2507 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
2509 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
2512 /* caller verifies at least 8 bytes in buf */
2514 extract_initial_length_and_fourcc (const guint8 * data, guint size,
2515 guint64 * plength, guint32 * pfourcc)
2520 length = QT_UINT32 (data);
2521 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2522 fourcc = QT_FOURCC (data + 4);
2523 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
2526 length = G_MAXUINT64;
2527 } else if (length == 1 && size >= 16) {
2528 /* this means we have an extended size, which is the 64 bit value of
2529 * the next 8 bytes */
2530 length = QT_UINT64 (data + 8);
2531 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2541 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
2543 guint32 version = 0;
2544 GstClockTime duration = 0;
2546 if (!gst_byte_reader_get_uint32_be (br, &version))
2551 if (!gst_byte_reader_get_uint64_be (br, &duration))
2556 if (!gst_byte_reader_get_uint32_be (br, &dur))
2561 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
2562 qtdemux->duration = duration;
2568 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
2574 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
2575 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
2577 if (!stream->parsed_trex && qtdemux->moov_node) {
2579 GstByteReader trex_data;
2581 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
2583 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
2586 guint32 id = 0, dur = 0, size = 0, flags = 0, dummy = 0;
2588 /* skip version/flags */
2589 if (!gst_byte_reader_skip (&trex_data, 4))
2591 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
2593 if (id != stream->track_id)
2595 /* sample description index; ignore */
2596 if (!gst_byte_reader_get_uint32_be (&trex_data, &dummy))
2598 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2600 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
2602 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
2605 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
2606 "duration %d, size %d, flags 0x%x", stream->track_id,
2609 stream->parsed_trex = TRUE;
2610 stream->def_sample_duration = dur;
2611 stream->def_sample_size = size;
2612 stream->def_sample_flags = flags;
2615 /* iterate all siblings */
2616 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
2622 *ds_duration = stream->def_sample_duration;
2623 *ds_size = stream->def_sample_size;
2624 *ds_flags = stream->def_sample_flags;
2626 /* even then, above values are better than random ... */
2627 if (G_UNLIKELY (!stream->parsed_trex)) {
2628 GST_WARNING_OBJECT (qtdemux,
2629 "failed to find fragment defaults for stream %d", stream->track_id);
2636 /* This method should be called whenever a more accurate duration might
2637 * have been found. It will update all relevant variables if/where needed
2640 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
2644 GstClockTime prevdur;
2646 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
2648 if (movdur > qtdemux->duration) {
2649 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
2650 GST_DEBUG_OBJECT (qtdemux,
2651 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
2652 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
2653 qtdemux->duration = movdur;
2654 GST_DEBUG_OBJECT (qtdemux,
2655 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
2656 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
2657 GST_TIME_ARGS (qtdemux->segment.stop));
2658 if (qtdemux->segment.duration == prevdur) {
2659 /* If the current segment has duration/stop identical to previous duration
2660 * update them also (because they were set at that point in time with
2661 * the wrong duration */
2662 /* We convert the value *from* the timescale version to avoid rounding errors */
2663 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
2664 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
2665 qtdemux->segment.duration = fixeddur;
2666 qtdemux->segment.stop = fixeddur;
2669 for (i = 0; i < qtdemux->n_streams; i++) {
2670 QtDemuxStream *stream = qtdemux->streams[i];
2672 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
2673 if (movdur > stream->duration) {
2674 GST_DEBUG_OBJECT (qtdemux,
2675 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
2676 GST_TIME_ARGS (duration));
2677 stream->duration = movdur;
2678 if (stream->dummy_segment) {
2679 /* Update all dummy values to new duration */
2680 stream->segments[0].stop_time = duration;
2681 stream->segments[0].duration = duration;
2682 stream->segments[0].media_stop = duration;
2690 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
2691 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
2692 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
2693 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts)
2695 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
2697 gint32 data_offset = 0;
2698 guint32 flags = 0, first_flags = 0, samples_count = 0;
2701 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
2702 QtDemuxSample *sample;
2703 gboolean ismv = FALSE;
2705 GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
2706 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
2707 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
2708 d_sample_size, d_sample_flags, *base_offset, decode_ts);
2710 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
2711 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
2715 /* presence of stss or not can't really tell us much,
2716 * and flags and so on tend to be marginally reliable in these files */
2717 if (stream->subtype == FOURCC_soun) {
2718 GST_DEBUG_OBJECT (qtdemux,
2719 "sound track in fragmented file; marking all keyframes");
2720 stream->all_keyframe = TRUE;
2723 if (!gst_byte_reader_skip (trun, 1) ||
2724 !gst_byte_reader_get_uint24_be (trun, &flags))
2727 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
2730 if (flags & TR_DATA_OFFSET) {
2731 /* note this is really signed */
2732 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
2734 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
2735 /* default base offset = first byte of moof */
2736 if (*base_offset == -1) {
2737 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
2738 *base_offset = moof_offset;
2740 *running_offset = *base_offset + data_offset;
2742 /* if no offset at all, that would mean data starts at moof start,
2743 * which is a bit wrong and is ismv crappy way, so compensate
2744 * assuming data is in mdat following moof */
2745 if (*base_offset == -1) {
2746 *base_offset = moof_offset + moof_length + 8;
2747 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
2750 if (*running_offset == -1)
2751 *running_offset = *base_offset;
2754 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
2756 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
2757 data_offset, flags, samples_count);
2759 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2760 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
2761 GST_DEBUG_OBJECT (qtdemux,
2762 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
2763 flags ^= TR_FIRST_SAMPLE_FLAGS;
2765 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
2767 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
2771 /* FIXME ? spec says other bits should also be checked to determine
2772 * entry size (and prefix size for that matter) */
2774 dur_offset = size_offset = 0;
2775 if (flags & TR_SAMPLE_DURATION) {
2776 GST_LOG_OBJECT (qtdemux, "entry duration present");
2777 dur_offset = entry_size;
2780 if (flags & TR_SAMPLE_SIZE) {
2781 GST_LOG_OBJECT (qtdemux, "entry size present");
2782 size_offset = entry_size;
2785 if (flags & TR_SAMPLE_FLAGS) {
2786 GST_LOG_OBJECT (qtdemux, "entry flags present");
2787 flags_offset = entry_size;
2790 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2791 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
2792 ct_offset = entry_size;
2796 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
2798 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
2800 if (stream->n_samples + samples_count >=
2801 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
2804 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
2805 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
2806 (stream->n_samples + samples_count) *
2807 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
2809 /* create a new array of samples if it's the first sample parsed */
2810 if (stream->n_samples == 0) {
2811 g_assert (stream->samples == NULL);
2812 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
2813 /* or try to reallocate it with space enough to insert the new samples */
2815 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
2816 stream->n_samples + samples_count);
2817 if (stream->samples == NULL)
2820 if (qtdemux->fragment_start != -1) {
2821 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
2822 qtdemux->fragment_start = -1;
2824 if (stream->n_samples == 0) {
2825 if (decode_ts > 0) {
2826 timestamp = decode_ts;
2827 } else if (stream->pending_seek != NULL) {
2828 /* if we don't have a timestamp from a tfdt box, we'll use the one
2829 * from the mfra seek table */
2830 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
2831 GST_TIME_ARGS (stream->pending_seek->ts));
2833 /* FIXME: this is not fully correct, the timestamp refers to the random
2834 * access sample refered to in the tfra entry, which may not necessarily
2835 * be the first sample in the tfrag/trun (but hopefully/usually is) */
2836 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
2841 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
2842 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
2843 GST_TIME_ARGS (gst_ts));
2845 /* subsequent fragments extend stream */
2847 stream->samples[stream->n_samples - 1].timestamp +
2848 stream->samples[stream->n_samples - 1].duration;
2850 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
2851 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
2852 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
2856 sample = stream->samples + stream->n_samples;
2857 for (i = 0; i < samples_count; i++) {
2858 guint32 dur, size, sflags, ct;
2860 /* first read sample data */
2861 if (flags & TR_SAMPLE_DURATION) {
2862 dur = QT_UINT32 (data + dur_offset);
2864 dur = d_sample_duration;
2866 if (flags & TR_SAMPLE_SIZE) {
2867 size = QT_UINT32 (data + size_offset);
2869 size = d_sample_size;
2871 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2873 sflags = first_flags;
2875 sflags = d_sample_flags;
2877 } else if (flags & TR_SAMPLE_FLAGS) {
2878 sflags = QT_UINT32 (data + flags_offset);
2880 sflags = d_sample_flags;
2882 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2883 ct = QT_UINT32 (data + ct_offset);
2889 /* fill the sample information */
2890 sample->offset = *running_offset;
2891 sample->pts_offset = ct;
2892 sample->size = size;
2893 sample->timestamp = timestamp;
2894 sample->duration = dur;
2895 /* sample-is-difference-sample */
2896 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
2897 * now idea how it relates to bitfield other than massive LE/BE confusion */
2898 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
2899 *running_offset += size;
2904 /* Update total duration if needed */
2905 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
2907 stream->n_samples += samples_count;
2909 if (stream->pending_seek != NULL)
2910 stream->pending_seek = NULL;
2916 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
2921 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
2927 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
2928 "be larger than %uMB (broken file?)", stream->n_samples,
2929 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
2934 /* find stream with @id */
2935 static inline QtDemuxStream *
2936 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
2938 QtDemuxStream *stream;
2942 if (G_UNLIKELY (!id)) {
2943 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
2947 /* try to get it fast and simple */
2948 if (G_LIKELY (id <= qtdemux->n_streams)) {
2949 stream = qtdemux->streams[id - 1];
2950 if (G_LIKELY (stream->track_id == id))
2954 /* linear search otherwise */
2955 for (i = 0; i < qtdemux->n_streams; i++) {
2956 stream = qtdemux->streams[i];
2957 if (stream->track_id == id)
2960 if (qtdemux->mss_mode) {
2961 /* mss should have only 1 stream anyway */
2962 return qtdemux->streams[0];
2969 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
2970 guint32 * fragment_number)
2972 if (!gst_byte_reader_skip (mfhd, 4))
2974 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
2979 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
2985 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
2986 QtDemuxStream ** stream, guint32 * default_sample_duration,
2987 guint32 * default_sample_size, guint32 * default_sample_flags,
2988 gint64 * base_offset)
2991 guint32 track_id = 0;
2993 if (!gst_byte_reader_skip (tfhd, 1) ||
2994 !gst_byte_reader_get_uint24_be (tfhd, &flags))
2997 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3000 *stream = qtdemux_find_stream (qtdemux, track_id);
3001 if (G_UNLIKELY (!*stream))
3002 goto unknown_stream;
3004 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3005 *base_offset = qtdemux->moof_offset;
3007 if (flags & TF_BASE_DATA_OFFSET)
3008 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3011 /* obtain stream defaults */
3012 qtdemux_parse_trex (qtdemux, *stream,
3013 default_sample_duration, default_sample_size, default_sample_flags);
3015 /* FIXME: Handle TF_SAMPLE_DESCRIPTION_INDEX properly */
3016 if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
3017 if (!gst_byte_reader_skip (tfhd, 4))
3020 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3021 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3024 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3025 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3028 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3029 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3036 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3041 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
3047 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3048 guint64 * decode_time)
3050 guint32 version = 0;
3052 if (!gst_byte_reader_get_uint32_be (br, &version))
3057 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3060 guint32 dec_time = 0;
3061 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3063 *decode_time = dec_time;
3066 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3073 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3078 /* Returns a pointer to a GstStructure containing the properties of
3079 * the stream sample identified by @sample_index. The caller must unref
3080 * the returned object after use. Returns NULL if unsuccessful. */
3081 static GstStructure *
3082 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3083 QtDemuxStream * stream, guint sample_index)
3085 QtDemuxCencSampleSetInfo *info = NULL;
3087 g_return_val_if_fail (stream != NULL, NULL);
3088 g_return_val_if_fail (stream->protected, NULL);
3089 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3091 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3093 /* Currently, cenc properties for groups of samples are not supported, so
3094 * simply return a copy of the default sample properties */
3095 return gst_structure_copy (info->default_properties);
3098 /* Parses the sizes of sample auxiliary information contained within a stream,
3099 * as given in a saiz box. Returns array of sample_count guint8 size values,
3100 * or NULL on failure */
3102 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3103 GstByteReader * br, guint32 * sample_count)
3107 guint8 default_info_size;
3109 g_return_val_if_fail (qtdemux != NULL, NULL);
3110 g_return_val_if_fail (stream != NULL, NULL);
3111 g_return_val_if_fail (br != NULL, NULL);
3112 g_return_val_if_fail (sample_count != NULL, NULL);
3114 if (!gst_byte_reader_get_uint32_be (br, &flags))
3118 /* aux_info_type and aux_info_type_parameter are ignored */
3119 if (!gst_byte_reader_skip (br, 8))
3123 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3125 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3127 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3129 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3132 if (default_info_size == 0) {
3133 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3137 info_sizes = g_new (guint8, *sample_count);
3138 memset (info_sizes, default_info_size, *sample_count);
3144 /* Parses the offset of sample auxiliary information contained within a stream,
3145 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3147 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3148 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3153 guint32 aux_info_type = 0;
3154 guint32 aux_info_type_parameter = 0;
3155 guint32 entry_count;
3159 g_return_val_if_fail (qtdemux != NULL, FALSE);
3160 g_return_val_if_fail (stream != NULL, FALSE);
3161 g_return_val_if_fail (br != NULL, FALSE);
3162 g_return_val_if_fail (offset != NULL, FALSE);
3164 if (!gst_byte_reader_get_uint8 (br, &version))
3167 if (!gst_byte_reader_get_uint24_be (br, &flags))
3171 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type))
3173 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3175 } else if (stream->protected) {
3176 aux_info_type = stream->protection_scheme_type;
3178 aux_info_type = stream->fourcc;
3182 *info_type = aux_info_type;
3183 if (info_type_parameter)
3184 *info_type_parameter = aux_info_type_parameter;
3186 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3187 "aux_info_type_parameter: %#06x",
3188 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3190 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3193 if (entry_count != 1) {
3194 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3199 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3201 *offset = (guint64) off_32;
3203 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3208 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3213 qtdemux_gst_structure_free (GstStructure * gststructure)
3216 gst_structure_free (gststructure);
3220 /* Parses auxiliary information relating to samples protected using Common
3221 * Encryption (cenc); the format of this information is defined in
3222 * ISO/IEC 23001-7. Returns TRUE if successful; FALSE otherwise. */
3224 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3225 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3227 QtDemuxCencSampleSetInfo *ss_info = NULL;
3231 g_return_val_if_fail (qtdemux != NULL, FALSE);
3232 g_return_val_if_fail (stream != NULL, FALSE);
3233 g_return_val_if_fail (br != NULL, FALSE);
3234 g_return_val_if_fail (stream->protected, FALSE);
3235 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3237 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3239 if (ss_info->crypto_info) {
3240 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
3241 g_ptr_array_free (ss_info->crypto_info, TRUE);
3244 ss_info->crypto_info =
3245 g_ptr_array_new_full (sample_count,
3246 (GDestroyNotify) qtdemux_gst_structure_free);
3248 for (i = 0; i < sample_count; ++i) {
3249 GstStructure *properties;
3250 guint16 n_subsamples = 0;
3255 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3256 if (properties == NULL) {
3257 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3260 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3261 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3262 gst_structure_free (properties);
3265 if (!gst_byte_reader_dup_data (br, iv_size, &data)) {
3266 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3267 gst_structure_free (properties);
3270 buf = gst_buffer_new_wrapped (data, iv_size);
3271 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3272 size = info_sizes[i];
3273 if (size > iv_size) {
3274 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3275 || !(n_subsamples > 0)) {
3276 gst_structure_free (properties);
3277 GST_ERROR_OBJECT (qtdemux,
3278 "failed to get subsample count for sample %u", i);
3281 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3282 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3283 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3285 gst_structure_free (properties);
3288 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3290 gst_structure_free (properties);
3293 gst_structure_set (properties,
3294 "subsample_count", G_TYPE_UINT, n_subsamples,
3295 "subsamples", GST_TYPE_BUFFER, buf, NULL);
3297 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3299 g_ptr_array_add (ss_info->crypto_info, properties);
3304 /* Converts a UUID in raw byte form to a string representation, as defined in
3305 * RFC 4122. The caller takes ownership of the returned string and is
3306 * responsible for freeing it after use. */
3308 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3310 const guint8 *uuid = (const guint8 *) uuid_bytes;
3312 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3313 "%02x%02x-%02x%02x%02x%02x%02x%02x",
3314 uuid[0], uuid[1], uuid[2], uuid[3],
3315 uuid[4], uuid[5], uuid[6], uuid[7],
3316 uuid[8], uuid[9], uuid[10], uuid[11],
3317 uuid[12], uuid[13], uuid[14], uuid[15]);
3320 /* Parses a Protection System Specific Header box (pssh), as defined in the
3321 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3322 * information needed by a specific content protection system in order to
3323 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3326 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
3328 gchar *sysid_string;
3329 guint32 pssh_size = QT_UINT32 (node->data);
3330 GstBuffer *pssh = NULL;
3331 GstEvent *event = NULL;
3332 guint32 parent_box_type;
3335 if (G_UNLIKELY (pssh_size < 32U)) {
3336 GST_ERROR_OBJECT (qtdemux, "invalid box size");
3341 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
3343 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
3345 pssh = gst_buffer_new_wrapped (g_memdup (node->data, pssh_size), pssh_size);
3346 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
3347 gst_buffer_get_size (pssh));
3349 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
3351 /* Push an event containing the pssh box onto the queues of all streams. */
3352 event = gst_event_new_protection (sysid_string, pssh,
3353 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
3354 for (i = 0; i < qtdemux->n_streams; ++i) {
3355 g_queue_push_tail (&qtdemux->streams[i]->protection_scheme_event_queue,
3356 gst_event_ref (event));
3358 g_free (sysid_string);
3359 gst_event_unref (event);
3360 gst_buffer_unref (pssh);
3365 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
3366 guint64 moof_offset, QtDemuxStream * stream)
3368 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
3369 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
3370 GNode *saiz_node, *saio_node, *pssh_node;
3371 GstByteReader saiz_data, saio_data;
3372 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
3373 gint64 base_offset, running_offset;
3376 /* NOTE @stream ignored */
3378 moof_node = g_node_new ((guint8 *) buffer);
3379 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
3380 qtdemux_node_dump (qtdemux, moof_node);
3382 /* Get fragment number from mfhd and check it's valid */
3384 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
3385 if (mfhd_node == NULL)
3387 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
3389 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
3391 /* unknown base_offset to start with */
3392 base_offset = running_offset = -1;
3393 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
3395 guint64 decode_time = 0;
3397 /* Fragment Header node */
3399 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
3403 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
3404 &ds_size, &ds_flags, &base_offset))
3407 /* The following code assumes at most a single set of sample auxiliary
3408 * data in the fragment (consisting of a saiz box and a corresponding saio
3409 * box); in theory, however, there could be multiple sets of sample
3410 * auxiliary data in a fragment. */
3412 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
3415 guint32 info_type = 0;
3417 guint32 info_type_parameter = 0;
3419 g_free (qtdemux->cenc_aux_info_sizes);
3421 qtdemux->cenc_aux_info_sizes =
3422 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
3423 &qtdemux->cenc_aux_sample_count);
3424 if (qtdemux->cenc_aux_info_sizes == NULL) {
3425 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
3429 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
3432 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
3433 g_free (qtdemux->cenc_aux_info_sizes);
3434 qtdemux->cenc_aux_info_sizes = NULL;
3438 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
3439 &info_type, &info_type_parameter, &offset))) {
3440 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
3441 g_free (qtdemux->cenc_aux_info_sizes);
3442 qtdemux->cenc_aux_info_sizes = NULL;
3445 if (base_offset > qtdemux->moof_offset)
3446 offset += (guint64) (base_offset - qtdemux->moof_offset);
3447 if (info_type == FOURCC_cenc && info_type_parameter == 0U) {
3449 if (offset > length) {
3450 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
3451 qtdemux->cenc_aux_info_offset = offset;
3453 gst_byte_reader_init (&br, buffer + offset, length - offset);
3454 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
3455 qtdemux->cenc_aux_info_sizes,
3456 qtdemux->cenc_aux_sample_count)) {
3457 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
3458 g_free (qtdemux->cenc_aux_info_sizes);
3459 qtdemux->cenc_aux_info_sizes = NULL;
3467 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
3470 GstClockTime decode_time_ts;
3472 /* We'll use decode_time to interpolate timestamps
3473 * in case the input timestamps are missing */
3474 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
3476 decode_time_ts = QTSTREAMTIME_TO_GSTTIME (stream, decode_time);
3478 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
3479 " (%" GST_TIME_FORMAT ")", decode_time,
3480 GST_TIME_ARGS (decode_time_ts));
3482 /* Discard the fragment buffer timestamp info to avoid using it.
3483 * Rely on tfdt instead as it is more accurate than the timestamp
3484 * that is fetched from a manifest/playlist and is usually
3486 qtdemux->fragment_start = -1;
3489 if (G_UNLIKELY (!stream)) {
3490 /* we lost track of offset, we'll need to regain it,
3491 * but can delay complaining until later or avoid doing so altogether */
3495 if (G_UNLIKELY (base_offset < -1))
3498 if (qtdemux->upstream_format_is_time)
3499 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
3501 /* Track Run node */
3503 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
3506 qtdemux_parse_trun (qtdemux, &trun_data, stream,
3507 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
3508 &running_offset, decode_time);
3509 /* iterate all siblings */
3510 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
3513 /* if no new base_offset provided for next traf,
3514 * base is end of current traf */
3515 base_offset = running_offset;
3516 running_offset = -1;
3518 /* iterate all siblings */
3519 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
3522 /* parse any protection system info */
3523 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
3525 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
3526 qtdemux_parse_pssh (qtdemux, pssh_node);
3527 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
3530 g_node_destroy (moof_node);
3535 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
3540 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
3545 GST_DEBUG_OBJECT (qtdemux, "lost offset");
3550 g_node_destroy (moof_node);
3551 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
3552 (_("This file is corrupt and cannot be played.")), (NULL));
3558 /* might be used if some day we actually use mfra & co
3559 * for random access to fragments,
3560 * but that will require quite some modifications and much less relying
3561 * on a sample array */
3565 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
3567 QtDemuxStream *stream;
3568 guint32 ver_flags, track_id, len, num_entries, i;
3569 guint value_size, traf_size, trun_size, sample_size;
3570 guint64 time = 0, moof_offset = 0;
3572 GstBuffer *buf = NULL;
3577 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
3579 if (!gst_byte_reader_skip (&tfra, 8))
3582 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
3585 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
3586 || !gst_byte_reader_get_uint32_be (&tfra, &len)
3587 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
3590 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
3592 stream = qtdemux_find_stream (qtdemux, track_id);
3594 goto unknown_trackid;
3596 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
3597 sample_size = (len & 3) + 1;
3598 trun_size = ((len & 12) >> 2) + 1;
3599 traf_size = ((len & 48) >> 4) + 1;
3601 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
3602 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
3604 if (num_entries == 0)
3607 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
3608 value_size + value_size + traf_size + trun_size + sample_size))
3611 g_free (stream->ra_entries);
3612 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
3613 stream->n_ra_entries = num_entries;
3615 for (i = 0; i < num_entries; i++) {
3616 qt_atom_parser_get_offset (&tfra, value_size, &time);
3617 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
3618 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
3619 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
3620 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
3622 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
3624 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
3625 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
3627 stream->ra_entries[i].ts = time;
3628 stream->ra_entries[i].moof_offset = moof_offset;
3630 /* don't want to go through the entire file and read all moofs at startup */
3632 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
3633 if (ret != GST_FLOW_OK)
3635 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
3636 moof_offset, stream);
3637 gst_buffer_unref (buf);
3641 check_update_duration (qtdemux, time);
3648 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
3653 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
3658 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
3664 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
3666 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
3667 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
3668 GstBuffer *mfro = NULL, *mfra = NULL;
3670 gboolean ret = FALSE;
3671 GNode *mfra_node, *tfra_node;
3672 guint64 mfra_offset = 0;
3673 guint32 fourcc, mfra_size;
3676 /* query upstream size in bytes */
3677 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
3678 goto size_query_failed;
3680 /* mfro box should be at the very end of the file */
3681 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
3682 if (flow != GST_FLOW_OK)
3685 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
3687 fourcc = QT_FOURCC (mfro_map.data + 4);
3688 if (fourcc != FOURCC_mfro)
3691 GST_INFO_OBJECT (qtdemux, "Found mfro box");
3692 if (mfro_map.size < 16)
3693 goto invalid_mfro_size;
3695 mfra_size = QT_UINT32 (mfro_map.data + 12);
3696 if (mfra_size >= len)
3697 goto invalid_mfra_size;
3699 mfra_offset = len - mfra_size;
3701 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
3702 mfra_offset, mfra_size);
3704 /* now get and parse mfra box */
3705 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
3706 if (flow != GST_FLOW_OK)
3709 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
3711 mfra_node = g_node_new ((guint8 *) mfra_map.data);
3712 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
3714 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
3717 qtdemux_parse_tfra (qtdemux, tfra_node);
3718 /* iterate all siblings */
3719 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
3721 g_node_destroy (mfra_node);
3723 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
3729 if (mfro_map.memory != NULL)
3730 gst_buffer_unmap (mfro, &mfro_map);
3731 gst_buffer_unref (mfro);
3734 if (mfra_map.memory != NULL)
3735 gst_buffer_unmap (mfra, &mfra_map);
3736 gst_buffer_unref (mfra);
3743 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
3748 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
3753 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
3758 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
3764 add_offset (guint64 offset, guint64 advance)
3766 /* Avoid 64-bit overflow by clamping */
3767 if (offset > G_MAXUINT64 - advance)
3769 return offset + advance;
3772 static GstFlowReturn
3773 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
3777 GstBuffer *buf = NULL;
3778 GstFlowReturn ret = GST_FLOW_OK;
3779 guint64 cur_offset = qtdemux->offset;
3782 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
3783 if (G_UNLIKELY (ret != GST_FLOW_OK))
3785 gst_buffer_map (buf, &map, GST_MAP_READ);
3786 if (G_LIKELY (map.size >= 8))
3787 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
3788 gst_buffer_unmap (buf, &map);
3789 gst_buffer_unref (buf);
3791 /* maybe we already got most we needed, so only consider this eof */
3792 if (G_UNLIKELY (length == 0)) {
3793 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
3794 (_("Invalid atom size.")),
3795 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
3796 GST_FOURCC_ARGS (fourcc)));
3803 /* record for later parsing when needed */
3804 if (!qtdemux->moof_offset) {
3805 qtdemux->moof_offset = qtdemux->offset;
3807 if (qtdemux_pull_mfro_mfra (qtdemux)) {
3810 qtdemux->offset += length; /* skip moof and keep going */
3812 if (qtdemux->got_moov) {
3813 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
3824 GST_LOG_OBJECT (qtdemux,
3825 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
3826 GST_FOURCC_ARGS (fourcc), cur_offset);
3827 qtdemux->offset = add_offset (qtdemux->offset, length);
3832 GstBuffer *moov = NULL;
3834 if (qtdemux->got_moov) {
3835 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
3836 qtdemux->offset = add_offset (qtdemux->offset, length);
3840 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
3841 if (ret != GST_FLOW_OK)
3843 gst_buffer_map (moov, &map, GST_MAP_READ);
3845 if (length != map.size) {
3846 /* Some files have a 'moov' atom at the end of the file which contains
3847 * a terminal 'free' atom where the body of the atom is missing.
3848 * Check for, and permit, this special case.
3850 if (map.size >= 8) {
3851 guint8 *final_data = map.data + (map.size - 8);
3852 guint32 final_length = QT_UINT32 (final_data);
3853 guint32 final_fourcc = QT_FOURCC (final_data + 4);
3855 if (final_fourcc == FOURCC_free
3856 && map.size + final_length - 8 == length) {
3857 /* Ok, we've found that special case. Allocate a new buffer with
3858 * that free atom actually present. */
3859 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
3860 gst_buffer_fill (newmoov, 0, map.data, map.size);
3861 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
3862 gst_buffer_unmap (moov, &map);
3863 gst_buffer_unref (moov);
3865 gst_buffer_map (moov, &map, GST_MAP_READ);
3870 if (length != map.size) {
3871 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
3872 (_("This file is incomplete and cannot be played.")),
3873 ("We got less than expected (received %" G_GSIZE_FORMAT
3874 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
3875 (guint) length, cur_offset));
3876 gst_buffer_unmap (moov, &map);
3877 gst_buffer_unref (moov);
3878 ret = GST_FLOW_ERROR;
3881 qtdemux->offset += length;
3883 qtdemux_parse_moov (qtdemux, map.data, length);
3884 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
3886 qtdemux_parse_tree (qtdemux);
3887 g_node_destroy (qtdemux->moov_node);
3888 gst_buffer_unmap (moov, &map);
3889 gst_buffer_unref (moov);
3890 qtdemux->moov_node = NULL;
3891 qtdemux->got_moov = TRUE;
3897 GstBuffer *ftyp = NULL;
3899 /* extract major brand; might come in handy for ISO vs QT issues */
3900 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
3901 if (ret != GST_FLOW_OK)
3903 qtdemux->offset += length;
3904 gst_buffer_map (ftyp, &map, GST_MAP_READ);
3905 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
3906 gst_buffer_unmap (ftyp, &map);
3907 gst_buffer_unref (ftyp);
3912 GstBuffer *uuid = NULL;
3914 /* uuid are extension atoms */
3915 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
3916 if (ret != GST_FLOW_OK)
3918 qtdemux->offset += length;
3919 gst_buffer_map (uuid, &map, GST_MAP_READ);
3920 qtdemux_parse_uuid (qtdemux, map.data, map.size);
3921 gst_buffer_unmap (uuid, &map);
3922 gst_buffer_unref (uuid);
3927 GstBuffer *sidx = NULL;
3928 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
3929 if (ret != GST_FLOW_OK)
3931 qtdemux->offset += length;
3932 gst_buffer_map (sidx, &map, GST_MAP_READ);
3933 qtdemux_parse_sidx (qtdemux, map.data, map.size);
3934 gst_buffer_unmap (sidx, &map);
3935 gst_buffer_unref (sidx);
3940 GstBuffer *unknown = NULL;
3942 GST_LOG_OBJECT (qtdemux,
3943 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
3944 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
3946 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
3947 if (ret != GST_FLOW_OK)
3949 gst_buffer_map (unknown, &map, GST_MAP_READ);
3950 GST_MEMDUMP ("Unknown tag", map.data, map.size);
3951 gst_buffer_unmap (unknown, &map);
3952 gst_buffer_unref (unknown);
3953 qtdemux->offset += length;
3959 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
3960 /* digested all data, show what we have */
3961 qtdemux_prepare_streams (qtdemux);
3962 ret = qtdemux_expose_streams (qtdemux);
3964 qtdemux->state = QTDEMUX_STATE_MOVIE;
3965 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
3972 /* Seeks to the previous keyframe of the indexed stream and
3973 * aligns other streams with respect to the keyframe timestamp
3974 * of indexed stream. Only called in case of Reverse Playback
3976 static GstFlowReturn
3977 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
3980 guint32 seg_idx = 0, k_index = 0;
3981 guint32 ref_seg_idx, ref_k_index;
3982 GstClockTime k_pos = 0, last_stop = 0;
3983 QtDemuxSegment *seg = NULL;
3984 QtDemuxStream *ref_str = NULL;
3985 guint64 seg_media_start_mov; /* segment media start time in mov format */
3988 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
3989 * and finally align all the other streams on that timestamp with their
3990 * respective keyframes */
3991 for (n = 0; n < qtdemux->n_streams; n++) {
3992 QtDemuxStream *str = qtdemux->streams[n];
3994 /* No candidate yet, take the first stream */
4000 /* So that stream has a segment, we prefer video streams */
4001 if (str->subtype == FOURCC_vide) {
4007 if (G_UNLIKELY (!ref_str)) {
4008 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4012 if (G_UNLIKELY (!ref_str->from_sample)) {
4013 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4017 /* So that stream has been playing from from_sample to to_sample. We will
4018 * get the timestamp of the previous sample and search for a keyframe before
4019 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4020 if (ref_str->subtype == FOURCC_vide) {
4021 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4022 ref_str->from_sample - 1);
4024 if (ref_str->from_sample >= 10)
4025 k_index = ref_str->from_sample - 10;
4031 ref_str->samples[k_index].timestamp +
4032 ref_str->samples[k_index].pts_offset;
4034 /* get current segment for that stream */
4035 seg = &ref_str->segments[ref_str->segment_index];
4036 /* Use segment start in original timescale for comparisons */
4037 seg_media_start_mov = seg->trak_media_start;
4039 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4040 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT "\n",
4041 k_index, target_ts, seg_media_start_mov,
4042 GST_TIME_ARGS (seg->media_start));
4044 /* Crawl back through segments to find the one containing this I frame */
4045 while (target_ts < seg_media_start_mov) {
4046 GST_DEBUG_OBJECT (qtdemux,
4047 "keyframe position (sample %u) is out of segment %u " " target %"
4048 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4049 ref_str->segment_index, target_ts, seg_media_start_mov);
4051 if (G_UNLIKELY (!ref_str->segment_index)) {
4052 /* Reached first segment, let's consider it's EOS */
4055 ref_str->segment_index--;
4056 seg = &ref_str->segments[ref_str->segment_index];
4057 /* Use segment start in original timescale for comparisons */
4058 seg_media_start_mov = seg->trak_media_start;
4060 /* Calculate time position of the keyframe and where we should stop */
4062 QTSTREAMTIME_TO_GSTTIME (ref_str,
4063 target_ts - seg->trak_media_start) + seg->time;
4065 QTSTREAMTIME_TO_GSTTIME (ref_str,
4066 ref_str->samples[ref_str->from_sample].timestamp -
4067 seg->trak_media_start) + seg->time;
4069 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4070 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4071 k_index, GST_TIME_ARGS (k_pos));
4073 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4074 qtdemux->segment.position = last_stop;
4075 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4076 GST_TIME_ARGS (last_stop));
4078 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4079 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4083 ref_seg_idx = ref_str->segment_index;
4084 ref_k_index = k_index;
4086 /* Align them all on this */
4087 for (n = 0; n < qtdemux->n_streams; n++) {
4089 GstClockTime seg_time = 0;
4090 QtDemuxStream *str = qtdemux->streams[n];
4092 /* aligning reference stream again might lead to backing up to yet another
4093 * keyframe (due to timestamp rounding issues),
4094 * potentially putting more load on downstream; so let's try to avoid */
4095 if (str == ref_str) {
4096 seg_idx = ref_seg_idx;
4097 seg = &str->segments[seg_idx];
4098 k_index = ref_k_index;
4099 GST_DEBUG_OBJECT (qtdemux, "reference stream %d segment %d, "
4100 "sample at index %d", n, ref_str->segment_index, k_index);
4102 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4103 GST_DEBUG_OBJECT (qtdemux,
4104 "stream %d align segment %d for keyframe pos %" GST_TIME_FORMAT, n,
4105 seg_idx, GST_TIME_ARGS (k_pos));
4107 /* get segment and time in the segment */
4108 seg = &str->segments[seg_idx];
4109 seg_time = k_pos - seg->time;
4111 /* get the media time in the segment.
4112 * No adjustment for empty "filler" segments */
4113 if (seg->media_start != GST_CLOCK_TIME_NONE)
4114 seg_time += seg->media_start;
4116 /* get the index of the sample with media time */
4117 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4118 GST_DEBUG_OBJECT (qtdemux,
4119 "stream %d sample for %" GST_TIME_FORMAT " at %u", n,
4120 GST_TIME_ARGS (seg_time), index);
4122 /* find previous keyframe */
4123 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index);
4126 /* Remember until where we want to go */
4127 str->to_sample = str->from_sample - 1;
4128 /* Define our time position */
4130 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4131 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4132 if (seg->media_start != GST_CLOCK_TIME_NONE)
4133 str->time_position -= seg->media_start;
4135 /* Now seek back in time */
4136 gst_qtdemux_move_stream (qtdemux, str, k_index);
4137 GST_DEBUG_OBJECT (qtdemux, "stream %d keyframe at %u, time position %"
4138 GST_TIME_FORMAT " playing from sample %u to %u", n, k_index,
4139 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4145 return GST_FLOW_EOS;
4148 /* activate the given segment number @seg_idx of @stream at time @offset.
4149 * @offset is an absolute global position over all the segments.
4151 * This will push out a NEWSEGMENT event with the right values and
4152 * position the stream index to the first decodable sample before
4156 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4157 guint32 seg_idx, GstClockTime offset)
4160 QtDemuxSegment *segment;
4161 guint32 index, kf_index;
4162 GstClockTime seg_time;
4163 GstClockTime start, stop, time;
4166 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
4167 seg_idx, GST_TIME_ARGS (offset));
4169 /* update the current segment */
4170 stream->segment_index = seg_idx;
4172 /* get the segment */
4173 segment = &stream->segments[seg_idx];
4175 if (G_UNLIKELY (offset < segment->time)) {
4176 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4177 GST_TIME_ARGS (segment->time));
4181 /* segment lies beyond total indicated duration */
4182 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4183 segment->time > qtdemux->segment.duration)) {
4184 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4185 " < segment->time %" GST_TIME_FORMAT,
4186 GST_TIME_ARGS (qtdemux->segment.duration),
4187 GST_TIME_ARGS (segment->time));
4191 /* get time in this segment */
4192 seg_time = offset - segment->time;
4194 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4195 GST_TIME_ARGS (seg_time));
4197 if (G_UNLIKELY (seg_time > segment->duration)) {
4198 GST_LOG_OBJECT (stream->pad,
4199 "seg_time > segment->duration %" GST_TIME_FORMAT,
4200 GST_TIME_ARGS (segment->duration));
4201 seg_time = segment->duration;
4204 /* qtdemux->segment.stop is in outside-time-realm, whereas
4205 * segment->media_stop is in track-time-realm.
4207 * In order to compare the two, we need to bring segment.stop
4208 * into the track-time-realm */
4210 stop = qtdemux->segment.stop;
4211 if (stop == GST_CLOCK_TIME_NONE)
4212 stop = qtdemux->segment.duration;
4213 if (stop == GST_CLOCK_TIME_NONE)
4214 stop = segment->media_stop;
4217 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4219 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4220 start = segment->time + seg_time;
4222 stop = start - seg_time + segment->duration;
4223 } else if (qtdemux->segment.rate >= 0) {
4224 start = MIN (segment->media_start + seg_time, stop);
4227 if (segment->media_start >= qtdemux->segment.start) {
4228 time = segment->time;
4230 time = segment->time + (qtdemux->segment.start - segment->media_start);
4233 start = MAX (segment->media_start, qtdemux->segment.start);
4234 stop = MIN (segment->media_start + seg_time, stop);
4237 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
4238 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
4239 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
4241 /* combine global rate with that of the segment */
4242 rate = segment->rate * qtdemux->segment.rate;
4244 /* Copy flags from main segment */
4245 stream->segment.flags = qtdemux->segment.flags;
4247 /* update the segment values used for clipping */
4248 stream->segment.offset = qtdemux->segment.offset;
4249 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
4250 stream->segment.applied_rate = qtdemux->segment.applied_rate;
4251 stream->segment.rate = rate;
4252 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
4253 stream->cslg_shift);
4254 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
4255 stream->cslg_shift);
4256 stream->segment.time = time;
4257 stream->segment.position = stream->segment.start;
4259 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
4262 /* now prepare and send the segment */
4264 event = gst_event_new_segment (&stream->segment);
4265 if (stream->segment_seqnum) {
4266 gst_event_set_seqnum (event, stream->segment_seqnum);
4268 gst_pad_push_event (stream->pad, event);
4269 /* assume we can send more data now */
4270 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
4271 /* clear to send tags on this pad now */
4272 gst_qtdemux_push_tags (qtdemux, stream);
4275 /* in the fragmented case, we pick a fragment that starts before our
4276 * desired position and rely on downstream to wait for a keyframe
4277 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
4278 * tfra entries tells us which trun/sample the key unit is in, but we don't
4279 * make use of this additional information at the moment) */
4280 if (qtdemux->fragmented) {
4281 stream->to_sample = G_MAXUINT32;
4285 /* We don't need to look for a sample in push-based */
4286 if (!qtdemux->pullbased)
4289 /* and move to the keyframe before the indicated media time of the
4291 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
4292 if (qtdemux->segment.rate >= 0) {
4293 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
4294 stream->to_sample = G_MAXUINT32;
4295 GST_DEBUG_OBJECT (stream->pad,
4296 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4297 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
4298 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4300 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
4301 stream->to_sample = index;
4302 GST_DEBUG_OBJECT (stream->pad,
4303 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4304 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
4305 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4308 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
4309 "this is an empty segment");
4313 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
4314 * encountered an error and printed a message so we return appropriately */
4318 /* we're at the right spot */
4319 if (index == stream->sample_index) {
4320 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
4324 /* find keyframe of the target index */
4325 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index);
4328 /* indent does stupid stuff with stream->samples[].timestamp */
4330 /* if we move forwards, we don't have to go back to the previous
4331 * keyframe since we already sent that. We can also just jump to
4332 * the keyframe right before the target index if there is one. */
4333 if (index > stream->sample_index) {
4334 /* moving forwards check if we move past a keyframe */
4335 if (kf_index > stream->sample_index) {
4336 GST_DEBUG_OBJECT (stream->pad,
4337 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4338 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4339 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4340 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4342 GST_DEBUG_OBJECT (stream->pad,
4343 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
4344 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
4345 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
4348 GST_DEBUG_OBJECT (stream->pad,
4349 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4350 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4351 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4352 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4360 /* prepare to get the current sample of @stream, getting essential values.
4362 * This function will also prepare and send the segment when needed.
4364 * Return FALSE if the stream is EOS.
4369 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
4370 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
4371 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
4372 gboolean * keyframe)
4374 QtDemuxSample *sample;
4375 GstClockTime time_position;
4378 g_return_val_if_fail (stream != NULL, FALSE);
4380 time_position = stream->time_position;
4381 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
4384 seg_idx = stream->segment_index;
4385 if (G_UNLIKELY (seg_idx == -1)) {
4386 /* find segment corresponding to time_position if we are looking
4388 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
4391 /* different segment, activate it, sample_index will be set. */
4392 if (G_UNLIKELY (stream->segment_index != seg_idx))
4393 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
4395 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->segments[stream->
4397 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
4399 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
4400 " prepare empty sample");
4403 *pts = *dts = time_position;
4404 *duration = seg->duration - (time_position - seg->time);
4411 if (stream->sample_index == -1)
4412 stream->sample_index = 0;
4414 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
4415 stream->sample_index, stream->n_samples);
4417 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
4418 if (!qtdemux->fragmented)
4421 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
4425 GST_OBJECT_LOCK (qtdemux);
4426 flow = qtdemux_add_fragmented_samples (qtdemux);
4427 GST_OBJECT_UNLOCK (qtdemux);
4429 if (flow != GST_FLOW_OK)
4432 while (stream->sample_index >= stream->n_samples);
4435 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4436 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4437 stream->sample_index);
4441 /* now get the info for the sample we're at */
4442 sample = &stream->samples[stream->sample_index];
4444 *dts = QTSAMPLE_DTS (stream, sample);
4445 *pts = QTSAMPLE_PTS (stream, sample);
4446 *offset = sample->offset;
4447 *size = sample->size;
4448 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
4449 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
4456 stream->time_position = GST_CLOCK_TIME_NONE;
4461 /* move to the next sample in @stream.
4463 * Moves to the next segment when needed.
4466 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
4468 QtDemuxSample *sample;
4469 QtDemuxSegment *segment;
4471 /* get current segment */
4472 segment = &stream->segments[stream->segment_index];
4474 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4475 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
4479 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
4480 /* Mark the stream as EOS */
4481 GST_DEBUG_OBJECT (qtdemux,
4482 "reached max allowed sample %u, mark EOS", stream->to_sample);
4483 stream->time_position = GST_CLOCK_TIME_NONE;
4487 /* move to next sample */
4488 stream->sample_index++;
4489 stream->offset_in_sample = 0;
4491 /* reached the last sample, we need the next segment */
4492 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
4495 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4496 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4497 stream->sample_index);
4501 /* get next sample */
4502 sample = &stream->samples[stream->sample_index];
4504 /* see if we are past the segment */
4505 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
4508 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
4509 /* inside the segment, update time_position, looks very familiar to
4510 * GStreamer segments, doesn't it? */
4511 stream->time_position =
4512 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
4514 /* not yet in segment, time does not yet increment. This means
4515 * that we are still prerolling keyframes to the decoder so it can
4516 * decode the first sample of the segment. */
4517 stream->time_position = segment->time;
4521 /* move to the next segment */
4524 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
4526 if (stream->segment_index == stream->n_segments - 1) {
4527 /* are we at the end of the last segment, we're EOS */
4528 stream->time_position = GST_CLOCK_TIME_NONE;
4530 /* else we're only at the end of the current segment */
4531 stream->time_position = segment->stop_time;
4533 /* make sure we select a new segment */
4535 /* accumulate previous segments */
4536 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
4537 stream->accumulated_base +=
4538 (stream->segment.stop -
4539 stream->segment.start) / ABS (stream->segment.rate);
4541 stream->segment_index = -1;
4546 gst_qtdemux_sync_streams (GstQTDemux * demux)
4550 if (demux->n_streams <= 1)
4553 for (i = 0; i < demux->n_streams; i++) {
4554 QtDemuxStream *stream;
4555 GstClockTime end_time;
4557 stream = demux->streams[i];
4562 /* TODO advance time on subtitle streams here, if any some day */
4564 /* some clips/trailers may have unbalanced streams at the end,
4565 * so send EOS on shorter stream to prevent stalling others */
4567 /* do not mess with EOS if SEGMENT seeking */
4568 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
4571 if (demux->pullbased) {
4572 /* loop mode is sample time based */
4573 if (!STREAM_IS_EOS (stream))
4576 /* push mode is byte position based */
4577 if (stream->n_samples &&
4578 stream->samples[stream->n_samples - 1].offset >= demux->offset)
4582 if (stream->sent_eos)
4585 /* only act if some gap */
4586 end_time = stream->segments[stream->n_segments - 1].stop_time;
4587 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
4588 ", stream end: %" GST_TIME_FORMAT,
4589 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
4590 if (GST_CLOCK_TIME_IS_VALID (end_time)
4591 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
4592 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
4593 GST_PAD_NAME (stream->pad));
4594 stream->sent_eos = TRUE;
4595 gst_pad_push_event (stream->pad, gst_event_new_eos ());
4600 /* EOS and NOT_LINKED need to be combined. This means that we return:
4602 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
4603 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
4605 static GstFlowReturn
4606 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
4609 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
4612 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
4615 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
4617 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
4621 /* the input buffer metadata must be writable. Returns NULL when the buffer is
4622 * completely clipped
4624 * Should be used only with raw buffers */
4626 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
4629 guint64 start, stop, cstart, cstop, diff;
4630 GstClockTime pts, duration;
4632 gint num_rate, denom_rate;
4637 osize = size = gst_buffer_get_size (buf);
4640 /* depending on the type, setup the clip parameters */
4641 if (stream->subtype == FOURCC_soun) {
4642 frame_size = stream->bytes_per_frame;
4643 num_rate = GST_SECOND;
4644 denom_rate = (gint) stream->rate;
4646 } else if (stream->subtype == FOURCC_vide) {
4648 num_rate = stream->fps_n;
4649 denom_rate = stream->fps_d;
4654 if (frame_size <= 0)
4655 goto bad_frame_size;
4657 /* we can only clip if we have a valid pts */
4658 pts = GST_BUFFER_PTS (buf);
4659 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
4662 duration = GST_BUFFER_DURATION (buf);
4664 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
4666 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
4670 stop = start + duration;
4672 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
4673 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
4676 /* see if some clipping happened */
4677 diff = cstart - start;
4683 /* bring clipped time to samples and to bytes */
4684 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
4687 GST_DEBUG_OBJECT (qtdemux,
4688 "clipping start to %" GST_TIME_FORMAT " %"
4689 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
4695 diff = stop - cstop;
4700 /* bring clipped time to samples and then to bytes */
4701 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
4703 GST_DEBUG_OBJECT (qtdemux,
4704 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
4705 " bytes", GST_TIME_ARGS (cstop), diff);
4710 if (offset != 0 || size != osize)
4711 gst_buffer_resize (buf, offset, size);
4713 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
4714 GST_BUFFER_PTS (buf) = pts;
4715 GST_BUFFER_DURATION (buf) = duration;
4719 /* dropped buffer */
4722 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
4727 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
4732 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
4737 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
4738 gst_buffer_unref (buf);
4743 /* the input buffer metadata must be writable,
4744 * but time/duration etc not yet set and need not be preserved */
4746 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
4753 /* not many cases for now */
4754 if (G_UNLIKELY (stream->fourcc == FOURCC_mp4s)) {
4755 /* send a one time dvd clut event */
4756 if (stream->pending_event && stream->pad)
4757 gst_pad_push_event (stream->pad, stream->pending_event);
4758 stream->pending_event = NULL;
4761 if (G_UNLIKELY (stream->subtype != FOURCC_text
4762 && stream->subtype != FOURCC_sbtl &&
4763 stream->subtype != FOURCC_subp)) {
4767 gst_buffer_map (buf, &map, GST_MAP_READ);
4769 /* empty buffer is sent to terminate previous subtitle */
4770 if (map.size <= 2) {
4771 gst_buffer_unmap (buf, &map);
4772 gst_buffer_unref (buf);
4775 if (stream->subtype == FOURCC_subp) {
4776 /* That's all the processing needed for subpictures */
4777 gst_buffer_unmap (buf, &map);
4781 nsize = GST_READ_UINT16_BE (map.data);
4782 nsize = MIN (nsize, map.size - 2);
4784 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
4787 /* takes care of UTF-8 validation or UTF-16 recognition,
4788 * no other encoding expected */
4789 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
4790 gst_buffer_unmap (buf, &map);
4792 gst_buffer_unref (buf);
4793 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
4795 /* this should not really happen unless the subtitle is corrupted */
4796 gst_buffer_unref (buf);
4800 /* FIXME ? convert optional subsequent style info to markup */
4805 /* Sets a buffer's attributes properly and pushes it downstream.
4806 * Also checks for additional actions and custom processing that may
4807 * need to be done first.
4809 static GstFlowReturn
4810 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
4811 QtDemuxStream * stream, GstBuffer * buf,
4812 GstClockTime dts, GstClockTime pts, GstClockTime duration,
4813 gboolean keyframe, GstClockTime position, guint64 byte_position)
4815 GstFlowReturn ret = GST_FLOW_OK;
4817 /* offset the timestamps according to the edit list */
4819 if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) {
4823 gst_buffer_map (buf, &map, GST_MAP_READ);
4824 url = g_strndup ((gchar *) map.data, map.size);
4825 gst_buffer_unmap (buf, &map);
4826 if (url != NULL && strlen (url) != 0) {
4827 /* we have RTSP redirect now */
4828 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
4829 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
4830 gst_structure_new ("redirect",
4831 "new-location", G_TYPE_STRING, url, NULL)));
4832 qtdemux->posted_redirect = TRUE;
4834 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
4840 /* position reporting */
4841 if (qtdemux->segment.rate >= 0) {
4842 qtdemux->segment.position = position;
4843 gst_qtdemux_sync_streams (qtdemux);
4846 if (G_UNLIKELY (!stream->pad)) {
4847 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
4848 gst_buffer_unref (buf);
4852 /* send out pending buffers */
4853 while (stream->buffers) {
4854 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
4856 if (G_UNLIKELY (stream->discont)) {
4857 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
4858 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
4859 stream->discont = FALSE;
4861 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
4864 gst_pad_push (stream->pad, buffer);
4866 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
4869 /* we're going to modify the metadata */
4870 buf = gst_buffer_make_writable (buf);
4872 if (G_UNLIKELY (stream->need_process))
4873 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
4879 GST_BUFFER_DTS (buf) = dts;
4880 GST_BUFFER_PTS (buf) = pts;
4881 GST_BUFFER_DURATION (buf) = duration;
4882 GST_BUFFER_OFFSET (buf) = -1;
4883 GST_BUFFER_OFFSET_END (buf) = -1;
4885 if (G_UNLIKELY (stream->rgb8_palette))
4886 gst_buffer_append_memory (buf, gst_memory_ref (stream->rgb8_palette));
4888 if (G_UNLIKELY (stream->padding)) {
4889 gst_buffer_resize (buf, stream->padding, -1);
4892 if (G_UNLIKELY (qtdemux->element_index)) {
4893 GstClockTime stream_time;
4896 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
4898 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
4899 GST_LOG_OBJECT (qtdemux,
4900 "adding association %" GST_TIME_FORMAT "-> %"
4901 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
4902 gst_index_add_association (qtdemux->element_index,
4904 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
4905 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
4906 GST_FORMAT_BYTES, byte_position, NULL);
4911 if (stream->need_clip)
4912 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
4914 if (G_UNLIKELY (buf == NULL))
4917 if (G_UNLIKELY (stream->discont)) {
4918 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
4919 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
4920 stream->discont = FALSE;
4922 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
4926 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
4927 stream->on_keyframe = FALSE;
4929 stream->on_keyframe = TRUE;
4933 GST_LOG_OBJECT (qtdemux,
4934 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
4935 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
4936 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
4937 GST_PAD_NAME (stream->pad));
4939 if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) {
4940 GstStructure *crypto_info;
4941 QtDemuxCencSampleSetInfo *info =
4942 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
4946 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
4947 gst_pad_push_event (stream->pad, event);
4950 index = stream->sample_index - (stream->n_samples - info->crypto_info->len);
4951 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
4952 /* steal structure from array */
4953 crypto_info = g_ptr_array_index (info->crypto_info, index);
4954 g_ptr_array_index (info->crypto_info, index) = NULL;
4955 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u]", index);
4956 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
4957 GST_ERROR_OBJECT (qtdemux, "failed to attach cenc metadata to buffer");
4961 ret = gst_pad_push (stream->pad, buf);
4963 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
4964 /* mark position in stream, we'll need this to know when to send GAP event */
4965 stream->segment.position = pts + duration;
4972 static const QtDemuxRandomAccessEntry *
4973 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4974 GstClockTime pos, gboolean after)
4976 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
4977 guint n_entries = stream->n_ra_entries;
4980 /* we assume the table is sorted */
4981 for (i = 0; i < n_entries; ++i) {
4982 if (entries[i].ts > pos)
4986 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
4987 * probably okay to assume that the index lists the very first fragment */
4994 return &entries[i - 1];
4998 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
5000 const QtDemuxRandomAccessEntry *best_entry = NULL;
5003 GST_OBJECT_LOCK (qtdemux);
5005 g_assert (qtdemux->n_streams > 0);
5007 for (i = 0; i < qtdemux->n_streams; i++) {
5008 const QtDemuxRandomAccessEntry *entry;
5009 QtDemuxStream *stream;
5010 gboolean is_audio_or_video;
5012 stream = qtdemux->streams[i];
5014 g_free (stream->samples);
5015 stream->samples = NULL;
5016 stream->n_samples = 0;
5017 stream->stbl_index = -1; /* no samples have yet been parsed */
5018 stream->sample_index = -1;
5020 if (stream->ra_entries == NULL)
5023 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
5024 is_audio_or_video = TRUE;
5026 is_audio_or_video = FALSE;
5029 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
5030 stream->time_position, !is_audio_or_video);
5032 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
5033 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
5035 stream->pending_seek = entry;
5037 /* decide position to jump to just based on audio/video tracks, not subs */
5038 if (!is_audio_or_video)
5041 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
5045 if (best_entry == NULL) {
5046 GST_OBJECT_UNLOCK (qtdemux);
5050 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
5051 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
5052 GST_TIME_ARGS (qtdemux->streams[0]->time_position),
5053 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
5055 qtdemux->moof_offset = best_entry->moof_offset;
5057 qtdemux_add_fragmented_samples (qtdemux);
5059 GST_OBJECT_UNLOCK (qtdemux);
5063 static GstFlowReturn
5064 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
5066 GstFlowReturn ret = GST_FLOW_OK;
5067 GstBuffer *buf = NULL;
5068 QtDemuxStream *stream;
5069 GstClockTime min_time;
5071 GstClockTime dts = GST_CLOCK_TIME_NONE;
5072 GstClockTime pts = GST_CLOCK_TIME_NONE;
5073 GstClockTime duration = 0;
5074 gboolean keyframe = FALSE;
5075 guint sample_size = 0;
5081 gst_qtdemux_push_pending_newsegment (qtdemux);
5083 if (qtdemux->fragmented_seek_pending) {
5084 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
5085 gst_qtdemux_do_fragmented_seek (qtdemux);
5086 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
5087 qtdemux->fragmented_seek_pending = FALSE;
5090 /* Figure out the next stream sample to output, min_time is expressed in
5091 * global time and runs over the edit list segments. */
5092 min_time = G_MAXUINT64;
5094 for (i = 0; i < qtdemux->n_streams; i++) {
5095 GstClockTime position;
5097 stream = qtdemux->streams[i];
5098 position = stream->time_position;
5100 /* position of -1 is EOS */
5101 if (position != GST_CLOCK_TIME_NONE && position < min_time) {
5102 min_time = position;
5107 if (G_UNLIKELY (index == -1)) {
5108 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
5112 /* check for segment end */
5113 if (G_UNLIKELY (qtdemux->segment.stop != -1
5114 && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
5115 || (qtdemux->segment.rate < 0
5116 && qtdemux->segment.start > min_time))
5117 && qtdemux->streams[index]->on_keyframe)) {
5118 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
5119 qtdemux->streams[index]->time_position = GST_CLOCK_TIME_NONE;
5123 /* gap events for subtitle streams */
5124 for (i = 0; i < qtdemux->n_streams; i++) {
5125 stream = qtdemux->streams[i];
5126 if (stream->pad && (stream->subtype == FOURCC_subp
5127 || stream->subtype == FOURCC_text
5128 || stream->subtype == FOURCC_sbtl)) {
5129 /* send one second gap events until the stream catches up */
5130 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
5131 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
5132 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
5133 stream->segment.position + GST_SECOND < min_time) {
5135 gst_event_new_gap (stream->segment.position, GST_SECOND);
5136 gst_pad_push_event (stream->pad, gap);
5137 stream->segment.position += GST_SECOND;
5142 stream = qtdemux->streams[index];
5143 if (stream->new_caps) {
5144 gst_qtdemux_configure_stream (qtdemux, stream);
5145 qtdemux_do_allocation (qtdemux, stream);
5148 /* fetch info for the current sample of this stream */
5149 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
5150 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
5153 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
5154 if (G_UNLIKELY (qtdemux->
5155 segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
5156 if (stream->subtype == FOURCC_vide && !keyframe) {
5157 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on stream %d", index);
5162 GST_DEBUG_OBJECT (qtdemux,
5163 "pushing from stream %d, empty %d offset %" G_GUINT64_FORMAT
5164 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
5165 ", duration %" GST_TIME_FORMAT, index, empty, offset, sample_size,
5166 GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
5168 if (G_UNLIKELY (empty)) {
5169 /* empty segment, push a gap and move to the next one */
5170 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
5171 stream->segment.position = pts + duration;
5175 /* hmm, empty sample, skip and move to next sample */
5176 if (G_UNLIKELY (sample_size <= 0))
5179 /* last pushed sample was out of boundary, goto next sample */
5180 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
5183 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
5186 GST_DEBUG_OBJECT (qtdemux,
5187 "size %d larger than stream max_buffer_size %d, trimming",
5188 sample_size, stream->max_buffer_size);
5190 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
5193 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
5196 if (stream->use_allocator) {
5197 /* if we have a per-stream allocator, use it */
5198 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
5201 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
5203 if (G_UNLIKELY (ret != GST_FLOW_OK))
5206 if (size != sample_size) {
5207 pts += gst_util_uint64_scale_int (GST_SECOND,
5208 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
5209 dts += gst_util_uint64_scale_int (GST_SECOND,
5210 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
5211 duration = gst_util_uint64_scale_int (GST_SECOND,
5212 size / stream->bytes_per_frame, stream->timescale);
5215 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
5216 dts, pts, duration, keyframe, min_time, offset);
5218 if (size != sample_size) {
5219 QtDemuxSample *sample = &stream->samples[stream->sample_index];
5220 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
5222 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
5223 sample->timestamp + stream->offset_in_sample / stream->bytes_per_frame);
5224 if (time_position >= segment->media_start) {
5225 /* inside the segment, update time_position, looks very familiar to
5226 * GStreamer segments, doesn't it? */
5227 stream->time_position = (time_position - segment->media_start) +
5230 /* not yet in segment, time does not yet increment. This means
5231 * that we are still prerolling keyframes to the decoder so it can
5232 * decode the first sample of the segment. */
5233 stream->time_position = segment->time;
5238 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
5239 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
5240 * we have no more data for the pad to push */
5241 if (ret == GST_FLOW_EOS)
5244 stream->offset_in_sample += size;
5245 if (stream->offset_in_sample >= sample_size) {
5246 gst_qtdemux_advance_sample (qtdemux, stream);
5251 gst_qtdemux_advance_sample (qtdemux, stream);
5259 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
5265 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
5266 /* EOS will be raised if all are EOS */
5273 gst_qtdemux_loop (GstPad * pad)
5275 GstQTDemux *qtdemux;
5279 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
5281 cur_offset = qtdemux->offset;
5282 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %d",
5283 cur_offset, qtdemux->state);
5285 switch (qtdemux->state) {
5286 case QTDEMUX_STATE_INITIAL:
5287 case QTDEMUX_STATE_HEADER:
5288 ret = gst_qtdemux_loop_state_header (qtdemux);
5290 case QTDEMUX_STATE_MOVIE:
5291 ret = gst_qtdemux_loop_state_movie (qtdemux);
5292 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
5293 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
5301 /* if something went wrong, pause */
5302 if (ret != GST_FLOW_OK)
5306 gst_object_unref (qtdemux);
5312 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
5313 (NULL), ("streaming stopped, invalid state"));
5314 gst_pad_pause_task (pad);
5315 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5320 const gchar *reason = gst_flow_get_name (ret);
5322 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
5324 gst_pad_pause_task (pad);
5326 /* fatal errors need special actions */
5328 if (ret == GST_FLOW_EOS) {
5329 if (qtdemux->n_streams == 0) {
5330 /* we have no streams, post an error */
5331 gst_qtdemux_post_no_playable_stream_error (qtdemux);
5333 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
5336 if ((stop = qtdemux->segment.stop) == -1)
5337 stop = qtdemux->segment.duration;
5339 if (qtdemux->segment.rate >= 0) {
5340 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
5341 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5342 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5343 GST_FORMAT_TIME, stop));
5344 gst_qtdemux_push_event (qtdemux,
5345 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
5347 /* For Reverse Playback */
5348 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
5349 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5350 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5351 GST_FORMAT_TIME, qtdemux->segment.start));
5352 gst_qtdemux_push_event (qtdemux,
5353 gst_event_new_segment_done (GST_FORMAT_TIME,
5354 qtdemux->segment.start));
5357 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
5358 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5360 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
5361 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
5362 (NULL), ("streaming stopped, reason %s", reason));
5363 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5372 * Returns if there are samples to be played.
5375 has_next_entry (GstQTDemux * demux)
5377 QtDemuxStream *stream;
5380 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
5382 for (i = 0; i < demux->n_streams; i++) {
5383 stream = demux->streams[i];
5385 if (stream->sample_index == -1) {
5386 stream->sample_index = 0;
5387 stream->offset_in_sample = 0;
5390 if (stream->sample_index >= stream->n_samples) {
5391 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
5394 GST_DEBUG_OBJECT (demux, "Found a sample");
5398 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
5405 * Returns the size of the first entry at the current offset.
5406 * If -1, there are none (which means EOS or empty file).
5409 next_entry_size (GstQTDemux * demux)
5411 QtDemuxStream *stream;
5414 guint64 smalloffs = (guint64) - 1;
5415 QtDemuxSample *sample;
5417 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
5420 for (i = 0; i < demux->n_streams; i++) {
5421 stream = demux->streams[i];
5423 if (stream->sample_index == -1) {
5424 stream->sample_index = 0;
5425 stream->offset_in_sample = 0;
5428 if (stream->sample_index >= stream->n_samples) {
5429 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
5433 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
5434 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
5435 stream->sample_index);
5439 sample = &stream->samples[stream->sample_index];
5441 GST_LOG_OBJECT (demux,
5442 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
5443 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
5444 sample->offset, sample->size);
5446 if (((smalloffs == -1)
5447 || (sample->offset < smalloffs)) && (sample->size)) {
5449 smalloffs = sample->offset;
5453 GST_LOG_OBJECT (demux,
5454 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
5455 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
5460 stream = demux->streams[smallidx];
5461 sample = &stream->samples[stream->sample_index];
5463 if (sample->offset >= demux->offset) {
5464 demux->todrop = sample->offset - demux->offset;
5465 return sample->size + demux->todrop;
5468 GST_DEBUG_OBJECT (demux,
5469 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
5474 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
5476 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
5478 gst_element_post_message (GST_ELEMENT_CAST (demux),
5479 gst_message_new_element (GST_OBJECT_CAST (demux),
5480 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
5484 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
5489 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
5492 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
5493 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
5494 GST_SEEK_TYPE_NONE, -1);
5496 /* store seqnum to drop flush events, they don't need to reach downstream */
5497 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
5498 res = gst_pad_push_event (demux->sinkpad, event);
5499 demux->offset_seek_seqnum = 0;
5504 /* check for seekable upstream, above and beyond a mere query */
5506 gst_qtdemux_check_seekability (GstQTDemux * demux)
5509 gboolean seekable = FALSE;
5510 gint64 start = -1, stop = -1;
5512 if (demux->upstream_size)
5515 query = gst_query_new_seeking (GST_FORMAT_BYTES);
5516 if (!gst_pad_peer_query (demux->sinkpad, query)) {
5517 GST_DEBUG_OBJECT (demux, "seeking query failed");
5521 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
5523 /* try harder to query upstream size if we didn't get it the first time */
5524 if (seekable && stop == -1) {
5525 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
5526 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
5529 /* if upstream doesn't know the size, it's likely that it's not seekable in
5530 * practice even if it technically may be seekable */
5531 if (seekable && (start != 0 || stop <= start)) {
5532 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
5537 gst_query_unref (query);
5539 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
5540 G_GUINT64_FORMAT ")", seekable, start, stop);
5541 demux->upstream_seekable = seekable;
5542 demux->upstream_size = seekable ? stop : -1;
5546 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
5548 g_return_if_fail (bytes <= demux->todrop);
5550 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
5551 gst_adapter_flush (demux->adapter, bytes);
5552 demux->neededbytes -= bytes;
5553 demux->offset += bytes;
5554 demux->todrop -= bytes;
5558 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
5560 if (G_UNLIKELY (demux->pending_newsegment)) {
5563 gst_qtdemux_push_pending_newsegment (demux);
5564 /* clear to send tags on all streams */
5565 for (i = 0; i < demux->n_streams; i++) {
5566 QtDemuxStream *stream;
5567 stream = demux->streams[i];
5568 gst_qtdemux_push_tags (demux, stream);
5569 if (stream->sparse) {
5570 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
5571 gst_pad_push_event (stream->pad,
5572 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
5579 gst_qtdemux_stream_send_initial_gap_segments (GstQTDemux * demux,
5580 QtDemuxStream * stream)
5584 /* Push any initial gap segments before proceeding to the
5586 for (i = 0; i < stream->n_segments; i++) {
5587 gst_qtdemux_activate_segment (demux, stream, i, stream->time_position);
5589 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
5590 GstClockTime ts, dur;
5593 ts = stream->time_position;
5595 stream->segments[i].duration - (stream->time_position -
5596 stream->segments[i].time);
5597 gap = gst_event_new_gap (ts, dur);
5598 stream->time_position += dur;
5600 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
5601 "segment: %" GST_PTR_FORMAT, gap);
5602 gst_pad_push_event (stream->pad, gap);
5604 /* Only support empty segment at the beginning followed by
5605 * one non-empty segment, this was checked when parsing the
5606 * edts atom, arriving here is unexpected */
5607 g_assert (i + 1 == stream->n_segments);
5613 static GstFlowReturn
5614 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
5618 demux = GST_QTDEMUX (parent);
5620 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
5623 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
5625 for (i = 0; i < demux->n_streams; i++) {
5626 demux->streams[i]->discont = TRUE;
5629 /* Reverse fragmented playback, need to flush all we have before
5630 * consuming a new fragment.
5631 * The samples array have the timestamps calculated by accumulating the
5632 * durations but this won't work for reverse playback of fragments as
5633 * the timestamps of a subsequent fragment should be smaller than the
5634 * previously received one. */
5635 if (demux->fragmented && demux->segment.rate < 0) {
5636 gst_qtdemux_process_adapter (demux, TRUE);
5637 for (i = 0; i < demux->n_streams; i++)
5638 gst_qtdemux_stream_flush_samples_data (demux, demux->streams[i]);
5642 gst_adapter_push (demux->adapter, inbuf);
5644 GST_DEBUG_OBJECT (demux,
5645 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
5646 demux->neededbytes, gst_adapter_available (demux->adapter));
5648 return gst_qtdemux_process_adapter (demux, FALSE);
5651 static GstFlowReturn
5652 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
5654 GstFlowReturn ret = GST_FLOW_OK;
5656 /* we never really mean to buffer that much */
5657 if (demux->neededbytes == -1) {
5661 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
5662 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
5664 GST_DEBUG_OBJECT (demux,
5665 "state:%d , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT,
5666 demux->state, demux->neededbytes, demux->offset);
5668 switch (demux->state) {
5669 case QTDEMUX_STATE_INITIAL:{
5674 gst_qtdemux_check_seekability (demux);
5676 data = gst_adapter_map (demux->adapter, demux->neededbytes);
5678 /* get fourcc/length, set neededbytes */
5679 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
5681 gst_adapter_unmap (demux->adapter);
5683 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
5684 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
5686 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
5687 (_("This file is invalid and cannot be played.")),
5688 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
5689 GST_FOURCC_ARGS (fourcc)));
5690 ret = GST_FLOW_ERROR;
5693 if (fourcc == FOURCC_mdat) {
5694 gint next_entry = next_entry_size (demux);
5695 if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
5696 /* we have the headers, start playback */
5697 demux->state = QTDEMUX_STATE_MOVIE;
5698 demux->neededbytes = next_entry;
5699 demux->mdatleft = size;
5701 /* no headers yet, try to get them */
5704 guint64 old, target;
5707 old = demux->offset;
5708 target = old + size;
5710 /* try to jump over the atom with a seek */
5711 /* only bother if it seems worth doing so,
5712 * and avoids possible upstream/server problems */
5713 if (demux->upstream_seekable &&
5714 demux->upstream_size > 4 * (1 << 20)) {
5715 res = qtdemux_seek_offset (demux, target);
5717 GST_DEBUG_OBJECT (demux, "skipping seek");
5722 GST_DEBUG_OBJECT (demux, "seek success");
5723 /* remember the offset fo the first mdat so we can seek back to it
5724 * after we have the headers */
5725 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
5726 demux->first_mdat = old;
5727 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
5730 /* seek worked, continue reading */
5731 demux->offset = target;
5732 demux->neededbytes = 16;
5733 demux->state = QTDEMUX_STATE_INITIAL;
5735 /* seek failed, need to buffer */
5736 demux->offset = old;
5737 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
5738 /* there may be multiple mdat (or alike) buffers */
5740 if (demux->mdatbuffer)
5741 bs = gst_buffer_get_size (demux->mdatbuffer);
5744 if (size + bs > 10 * (1 << 20))
5746 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
5747 demux->neededbytes = size;
5748 if (!demux->mdatbuffer)
5749 demux->mdatoffset = demux->offset;
5752 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
5753 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
5754 (_("This file is invalid and cannot be played.")),
5755 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
5756 GST_FOURCC_ARGS (fourcc), size));
5757 ret = GST_FLOW_ERROR;
5760 /* this means we already started buffering and still no moov header,
5761 * let's continue buffering everything till we get moov */
5762 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
5763 || fourcc == FOURCC_moof))
5765 demux->neededbytes = size;
5766 demux->state = QTDEMUX_STATE_HEADER;
5770 case QTDEMUX_STATE_HEADER:{
5774 GST_DEBUG_OBJECT (demux, "In header");
5776 data = gst_adapter_map (demux->adapter, demux->neededbytes);
5778 /* parse the header */
5779 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
5781 if (fourcc == FOURCC_moov) {
5783 gboolean got_samples = FALSE;
5785 /* in usual fragmented setup we could try to scan for more
5786 * and end up at the the moov (after mdat) again */
5787 if (demux->got_moov && demux->n_streams > 0 &&
5789 || demux->last_moov_offset == demux->offset)) {
5790 GST_DEBUG_OBJECT (demux,
5791 "Skipping moov atom as we have (this) one already");
5793 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
5795 if (demux->got_moov && demux->fragmented) {
5796 GST_DEBUG_OBJECT (demux,
5797 "Got a second moov, clean up data from old one");
5798 if (demux->moov_node)
5799 g_node_destroy (demux->moov_node);
5800 demux->moov_node = NULL;
5801 demux->moov_node_compressed = NULL;
5803 /* prepare newsegment to send when streaming actually starts */
5804 if (!demux->pending_newsegment)
5805 demux->pending_newsegment =
5806 gst_event_new_segment (&demux->segment);
5809 demux->last_moov_offset = demux->offset;
5811 qtdemux_parse_moov (demux, data, demux->neededbytes);
5812 qtdemux_node_dump (demux, demux->moov_node);
5813 qtdemux_parse_tree (demux);
5814 qtdemux_prepare_streams (demux);
5816 for (n = 0; n < demux->n_streams; n++) {
5817 QtDemuxStream *stream = demux->streams[n];
5818 got_samples |= stream->stbl_index >= 0;
5820 if (!demux->fragmented || got_samples) {
5821 if (!demux->got_moov) {
5822 qtdemux_expose_streams (demux);
5824 for (n = 0; n < demux->n_streams; n++) {
5825 QtDemuxStream *stream = demux->streams[n];
5826 gst_qtdemux_configure_stream (demux, stream);
5829 gst_qtdemux_check_send_pending_segment (demux);
5830 demux->pending_configure = FALSE;
5832 demux->pending_configure = TRUE;
5835 demux->got_moov = TRUE;
5837 /* fragmented streams headers shouldn't contain edts atoms */
5838 if (!demux->fragmented) {
5839 for (n = 0; n < demux->n_streams; n++) {
5840 gst_qtdemux_stream_send_initial_gap_segments (demux,
5845 g_node_destroy (demux->moov_node);
5846 demux->moov_node = NULL;
5847 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
5849 } else if (fourcc == FOURCC_moof) {
5850 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
5852 GstClockTime prev_pts;
5853 guint64 prev_offset;
5856 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
5859 * The timestamp of the moof buffer is relevant as some scenarios
5860 * won't have the initial timestamp in the atoms. Whenever a new
5861 * buffer has started, we get that buffer's PTS and use it as a base
5862 * timestamp for the trun entries.
5864 * To keep track of the current buffer timestamp and starting point
5865 * we use gst_adapter_prev_pts that gives us the PTS and the distance
5866 * from the beggining of the buffer, with the distance and demux->offset
5867 * we know if it is still the same buffer or not.
5869 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
5870 prev_offset = demux->offset - dist;
5871 if (demux->fragment_start_offset == -1
5872 || prev_offset > demux->fragment_start_offset) {
5873 demux->fragment_start_offset = prev_offset;
5874 demux->fragment_start = prev_pts;
5875 GST_DEBUG_OBJECT (demux,
5876 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
5877 GST_TIME_FORMAT, demux->fragment_start_offset,
5878 GST_TIME_ARGS (demux->fragment_start));
5881 demux->moof_offset = demux->offset;
5882 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
5883 demux->offset, NULL)) {
5884 gst_adapter_unmap (demux->adapter);
5885 ret = GST_FLOW_ERROR;
5888 /* in MSS we need to expose the pads after the first moof as we won't get a moov
5889 * Also, fragmented format need to be exposed if a moov have no valid sample data */
5890 if (demux->mss_mode || demux->pending_configure) {
5891 if (!demux->exposed) {
5892 if (!demux->pending_newsegment) {
5894 gst_segment_init (&segment, GST_FORMAT_TIME);
5895 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
5896 demux->pending_newsegment = gst_event_new_segment (&segment);
5898 qtdemux_expose_streams (demux);
5900 for (n = 0; n < demux->n_streams; n++) {
5901 QtDemuxStream *stream = demux->streams[n];
5902 gst_qtdemux_configure_stream (demux, stream);
5905 gst_qtdemux_check_send_pending_segment (demux);
5906 demux->pending_configure = FALSE;
5909 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
5911 } else if (fourcc == FOURCC_ftyp) {
5912 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
5913 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
5914 } else if (fourcc == FOURCC_uuid) {
5915 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
5916 qtdemux_parse_uuid (demux, data, demux->neededbytes);
5917 } else if (fourcc == FOURCC_sidx) {
5918 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
5919 qtdemux_parse_sidx (demux, data, demux->neededbytes);
5921 GST_WARNING_OBJECT (demux,
5922 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
5923 GST_FOURCC_ARGS (fourcc));
5924 /* Let's jump that one and go back to initial state */
5926 gst_adapter_unmap (demux->adapter);
5929 if (demux->mdatbuffer && demux->n_streams) {
5930 gsize remaining_data_size = 0;
5932 /* the mdat was before the header */
5933 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
5934 demux->n_streams, demux->mdatbuffer);
5935 /* restore our adapter/offset view of things with upstream;
5936 * put preceding buffered data ahead of current moov data.
5937 * This should also handle evil mdat, moov, mdat cases and alike */
5938 gst_adapter_flush (demux->adapter, demux->neededbytes);
5940 /* Store any remaining data after the mdat for later usage */
5941 remaining_data_size = gst_adapter_available (demux->adapter);
5942 if (remaining_data_size > 0) {
5943 g_assert (demux->restoredata_buffer == NULL);
5944 demux->restoredata_buffer =
5945 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
5946 demux->restoredata_offset = demux->offset + demux->neededbytes;
5947 GST_DEBUG_OBJECT (demux,
5948 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
5949 G_GUINT64_FORMAT, remaining_data_size,
5950 demux->restoredata_offset);
5953 gst_adapter_push (demux->adapter, demux->mdatbuffer);
5954 demux->mdatbuffer = NULL;
5955 demux->offset = demux->mdatoffset;
5956 demux->neededbytes = next_entry_size (demux);
5957 demux->state = QTDEMUX_STATE_MOVIE;
5958 demux->mdatleft = gst_adapter_available (demux->adapter);
5960 GST_DEBUG_OBJECT (demux, "Carrying on normally");
5961 gst_adapter_flush (demux->adapter, demux->neededbytes);
5963 /* only go back to the mdat if there are samples to play */
5964 if (demux->got_moov && demux->first_mdat != -1
5965 && has_next_entry (demux)) {
5968 /* we need to seek back */
5969 res = qtdemux_seek_offset (demux, demux->first_mdat);
5971 demux->offset = demux->first_mdat;
5973 GST_DEBUG_OBJECT (demux, "Seek back failed");
5976 demux->offset += demux->neededbytes;
5978 demux->neededbytes = 16;
5979 demux->state = QTDEMUX_STATE_INITIAL;
5984 case QTDEMUX_STATE_BUFFER_MDAT:{
5988 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
5990 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
5991 gst_buffer_extract (buf, 0, fourcc, 4);
5992 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
5993 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
5994 if (demux->mdatbuffer)
5995 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
5997 demux->mdatbuffer = buf;
5998 demux->offset += demux->neededbytes;
5999 demux->neededbytes = 16;
6000 demux->state = QTDEMUX_STATE_INITIAL;
6001 gst_qtdemux_post_progress (demux, 1, 1);
6005 case QTDEMUX_STATE_MOVIE:{
6006 QtDemuxStream *stream = NULL;
6007 QtDemuxSample *sample;
6009 GstClockTime dts, pts, duration;
6012 GST_DEBUG_OBJECT (demux,
6013 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
6015 if (demux->fragmented) {
6016 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
6018 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
6019 /* if needed data starts within this atom,
6020 * then it should not exceed this atom */
6021 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
6022 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6023 (_("This file is invalid and cannot be played.")),
6024 ("sample data crosses atom boundary"));
6025 ret = GST_FLOW_ERROR;
6028 demux->mdatleft -= demux->neededbytes;
6030 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
6031 /* so we are dropping more than left in this atom */
6032 gst_qtdemux_drop_data (demux, demux->mdatleft);
6033 demux->mdatleft = 0;
6035 /* need to resume atom parsing so we do not miss any other pieces */
6036 demux->state = QTDEMUX_STATE_INITIAL;
6037 demux->neededbytes = 16;
6039 /* check if there was any stored post mdat data from previous buffers */
6040 if (demux->restoredata_buffer) {
6041 g_assert (gst_adapter_available (demux->adapter) == 0);
6043 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
6044 demux->restoredata_buffer = NULL;
6045 demux->offset = demux->restoredata_offset;
6052 if (demux->todrop) {
6053 if (demux->cenc_aux_info_offset > 0) {
6057 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
6058 data = gst_adapter_map (demux->adapter, demux->todrop);
6059 gst_byte_reader_init (&br, data + 8, demux->todrop);
6060 if (!qtdemux_parse_cenc_aux_info (demux, demux->streams[0], &br,
6061 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
6062 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
6063 ret = GST_FLOW_ERROR;
6064 gst_adapter_unmap (demux->adapter);
6065 g_free (demux->cenc_aux_info_sizes);
6066 demux->cenc_aux_info_sizes = NULL;
6069 demux->cenc_aux_info_offset = 0;
6070 g_free (demux->cenc_aux_info_sizes);
6071 demux->cenc_aux_info_sizes = NULL;
6072 gst_adapter_unmap (demux->adapter);
6074 gst_qtdemux_drop_data (demux, demux->todrop);
6078 /* initial newsegment sent here after having added pads,
6079 * possible others in sink_event */
6080 gst_qtdemux_check_send_pending_segment (demux);
6082 /* Figure out which stream this packet belongs to */
6083 for (i = 0; i < demux->n_streams; i++) {
6084 stream = demux->streams[i];
6085 if (stream->sample_index >= stream->n_samples)
6087 GST_LOG_OBJECT (demux,
6088 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
6089 " / size:%d)", i, stream->sample_index,
6090 stream->samples[stream->sample_index].offset,
6091 stream->samples[stream->sample_index].size);
6093 if (stream->samples[stream->sample_index].offset == demux->offset)
6097 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
6098 goto unknown_stream;
6100 if (stream->new_caps) {
6101 gst_qtdemux_configure_stream (demux, stream);
6104 /* Put data in a buffer, set timestamps, caps, ... */
6105 sample = &stream->samples[stream->sample_index];
6107 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
6108 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
6109 GST_FOURCC_ARGS (stream->fourcc));
6111 dts = QTSAMPLE_DTS (stream, sample);
6112 pts = QTSAMPLE_PTS (stream, sample);
6113 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
6114 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
6116 /* check for segment end */
6117 if (G_UNLIKELY (demux->segment.stop != -1
6118 && demux->segment.stop <= pts && stream->on_keyframe)) {
6119 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
6120 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
6122 /* skip this data, stream is EOS */
6123 gst_adapter_flush (demux->adapter, demux->neededbytes);
6125 /* check if all streams are eos */
6127 for (i = 0; i < demux->n_streams; i++) {
6128 if (!STREAM_IS_EOS (demux->streams[i])) {
6134 if (ret == GST_FLOW_EOS) {
6135 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
6142 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6144 /* FIXME: should either be an assert or a plain check */
6145 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
6147 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
6148 dts, pts, duration, keyframe, dts, demux->offset);
6152 ret = gst_qtdemux_combine_flows (demux, stream, ret);
6153 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)
6154 goto non_ok_unlinked_flow;
6156 /* skip this data, stream is EOS */
6157 gst_adapter_flush (demux->adapter, demux->neededbytes);
6160 stream->sample_index++;
6161 stream->offset_in_sample = 0;
6163 /* update current offset and figure out size of next buffer */
6164 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
6165 demux->offset, demux->neededbytes);
6166 demux->offset += demux->neededbytes;
6167 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
6170 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
6171 if (demux->fragmented) {
6172 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
6173 /* there may be more to follow, only finish this atom */
6174 demux->todrop = demux->mdatleft;
6175 demux->neededbytes = demux->todrop;
6187 /* when buffering movie data, at least show user something is happening */
6188 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
6189 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
6190 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
6191 demux->neededbytes);
6198 non_ok_unlinked_flow:
6200 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
6201 gst_flow_get_name (ret));
6206 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
6207 ret = GST_FLOW_ERROR;
6212 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
6218 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
6219 (NULL), ("qtdemuxer invalid state %d", demux->state));
6220 ret = GST_FLOW_ERROR;
6225 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
6226 (NULL), ("no 'moov' atom within the first 10 MB"));
6227 ret = GST_FLOW_ERROR;
6233 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
6238 query = gst_query_new_scheduling ();
6240 if (!gst_pad_peer_query (sinkpad, query)) {
6241 gst_query_unref (query);
6245 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
6246 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
6247 gst_query_unref (query);
6252 GST_DEBUG_OBJECT (sinkpad, "activating pull");
6253 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
6257 GST_DEBUG_OBJECT (sinkpad, "activating push");
6258 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
6263 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
6264 GstPadMode mode, gboolean active)
6267 GstQTDemux *demux = GST_QTDEMUX (parent);
6270 case GST_PAD_MODE_PUSH:
6271 demux->pullbased = FALSE;
6274 case GST_PAD_MODE_PULL:
6276 demux->pullbased = TRUE;
6277 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
6280 res = gst_pad_stop_task (sinkpad);
6292 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
6294 return g_malloc (items * size);
6298 qtdemux_zfree (void *opaque, void *addr)
6304 qtdemux_inflate (void *z_buffer, guint z_length, guint length)
6310 z = g_new0 (z_stream, 1);
6311 z->zalloc = qtdemux_zalloc;
6312 z->zfree = qtdemux_zfree;
6315 z->next_in = z_buffer;
6316 z->avail_in = z_length;
6318 buffer = (guint8 *) g_malloc (length);
6319 ret = inflateInit (z);
6320 while (z->avail_in > 0) {
6321 if (z->avail_out == 0) {
6323 buffer = (guint8 *) g_realloc (buffer, length);
6324 z->next_out = buffer + z->total_out;
6325 z->avail_out = 1024;
6327 ret = inflate (z, Z_SYNC_FLUSH);
6331 if (ret != Z_STREAM_END) {
6332 g_warning ("inflate() returned %d", ret);
6338 #endif /* HAVE_ZLIB */
6341 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
6345 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
6347 /* counts as header data */
6348 qtdemux->header_size += length;
6350 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
6351 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
6353 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
6359 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
6360 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
6361 if (dcom == NULL || cmvd == NULL)
6362 goto invalid_compression;
6364 method = QT_FOURCC ((guint8 *) dcom->data + 8);
6368 guint uncompressed_length;
6369 guint compressed_length;
6372 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
6373 compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12;
6374 GST_LOG ("length = %u", uncompressed_length);
6377 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
6378 compressed_length, uncompressed_length);
6380 qtdemux->moov_node_compressed = qtdemux->moov_node;
6381 qtdemux->moov_node = g_node_new (buf);
6383 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
6384 uncompressed_length);
6387 #endif /* HAVE_ZLIB */
6389 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
6390 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
6397 invalid_compression:
6399 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
6405 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
6408 while (G_UNLIKELY (buf < end)) {
6412 if (G_UNLIKELY (buf + 4 > end)) {
6413 GST_LOG_OBJECT (qtdemux, "buffer overrun");
6416 len = QT_UINT32 (buf);
6417 if (G_UNLIKELY (len == 0)) {
6418 GST_LOG_OBJECT (qtdemux, "empty container");
6421 if (G_UNLIKELY (len < 8)) {
6422 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
6425 if (G_UNLIKELY (len > (end - buf))) {
6426 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
6427 (gint) (end - buf));
6431 child = g_node_new ((guint8 *) buf);
6432 g_node_append (node, child);
6433 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
6434 qtdemux_parse_node (qtdemux, child, buf, len);
6442 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
6445 int len = QT_UINT32 (xdxt->data);
6446 guint8 *buf = xdxt->data;
6447 guint8 *end = buf + len;
6450 /* skip size and type */
6458 size = QT_UINT32 (buf);
6459 type = QT_FOURCC (buf + 4);
6461 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
6463 if (buf + size > end || size <= 0)
6469 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
6470 GST_FOURCC_ARGS (type));
6474 buffer = gst_buffer_new_and_alloc (size);
6475 gst_buffer_fill (buffer, 0, buf, size);
6476 stream->buffers = g_slist_append (stream->buffers, buffer);
6477 GST_LOG_OBJECT (qtdemux, "parsing theora header");
6480 buffer = gst_buffer_new_and_alloc (size);
6481 gst_buffer_fill (buffer, 0, buf, size);
6482 stream->buffers = g_slist_append (stream->buffers, buffer);
6483 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
6486 buffer = gst_buffer_new_and_alloc (size);
6487 gst_buffer_fill (buffer, 0, buf, size);
6488 stream->buffers = g_slist_append (stream->buffers, buffer);
6489 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
6492 GST_WARNING_OBJECT (qtdemux,
6493 "unknown theora cookie %" GST_FOURCC_FORMAT,
6494 GST_FOURCC_ARGS (type));
6503 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
6507 guint32 node_length = 0;
6508 const QtNodeType *type;
6511 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
6513 if (G_UNLIKELY (length < 8))
6514 goto not_enough_data;
6516 node_length = QT_UINT32 (buffer);
6517 fourcc = QT_FOURCC (buffer + 4);
6519 /* ignore empty nodes */
6520 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
6523 type = qtdemux_type_get (fourcc);
6525 end = buffer + length;
6527 GST_LOG_OBJECT (qtdemux,
6528 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
6529 GST_FOURCC_ARGS (fourcc), node_length, type->name);
6531 if (node_length > length)
6532 goto broken_atom_size;
6534 if (type->flags & QT_FLAG_CONTAINER) {
6535 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
6540 if (node_length < 20) {
6541 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
6544 GST_DEBUG_OBJECT (qtdemux,
6545 "parsing stsd (sample table, sample description) atom");
6546 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
6547 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
6557 /* also read alac (or whatever) in stead of mp4a in the following,
6558 * since a similar layout is used in other cases as well */
6559 if (fourcc == FOURCC_mp4a)
6564 /* There are two things we might encounter here: a true mp4a atom, and
6565 an mp4a entry in an stsd atom. The latter is what we're interested
6566 in, and it looks like an atom, but isn't really one. The true mp4a
6567 atom is short, so we detect it based on length here. */
6568 if (length < min_size) {
6569 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
6570 GST_FOURCC_ARGS (fourcc));
6574 /* 'version' here is the sound sample description version. Types 0 and
6575 1 are documented in the QTFF reference, but type 2 is not: it's
6576 described in Apple header files instead (struct SoundDescriptionV2
6578 version = QT_UINT16 (buffer + 16);
6580 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
6581 GST_FOURCC_ARGS (fourcc), version);
6583 /* parse any esds descriptors */
6595 GST_WARNING_OBJECT (qtdemux,
6596 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
6597 GST_FOURCC_ARGS (fourcc), version);
6602 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
6619 /* codec_data is contained inside these atoms, which all have
6620 * the same format. */
6622 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
6623 GST_FOURCC_ARGS (fourcc));
6624 version = QT_UINT32 (buffer + 16);
6625 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
6626 if (1 || version == 0x00000000) {
6627 buf = buffer + 0x32;
6629 /* FIXME Quicktime uses PASCAL string while
6630 * the iso format uses C strings. Check the file
6631 * type before attempting to parse the string here. */
6632 tlen = QT_UINT8 (buf);
6633 GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
6635 GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
6636 /* the string has a reserved space of 32 bytes so skip
6637 * the remaining 31 */
6639 buf += 4; /* and 4 bytes reserved */
6641 GST_MEMDUMP_OBJECT (qtdemux, "mp4v", buf, end - buf);
6643 qtdemux_parse_container (qtdemux, node, buf, end);
6649 GST_MEMDUMP_OBJECT (qtdemux, "H264", buffer, end - buffer);
6650 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6655 GST_MEMDUMP_OBJECT (qtdemux, "avc1", buffer, end - buffer);
6656 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6661 GST_MEMDUMP_OBJECT (qtdemux, "avc3", buffer, end - buffer);
6662 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6667 GST_MEMDUMP_OBJECT (qtdemux, "H265", buffer, end - buffer);
6668 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6673 GST_MEMDUMP_OBJECT (qtdemux, "hvc1", buffer, end - buffer);
6674 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6679 GST_MEMDUMP_OBJECT (qtdemux, "hev1", buffer, end - buffer);
6680 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6685 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
6690 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
6691 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
6696 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
6697 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
6698 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
6706 version = QT_UINT32 (buffer + 12);
6707 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
6714 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
6719 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
6724 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
6729 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
6734 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
6739 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
6743 if (!strcmp (type->name, "unknown"))
6744 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
6748 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
6749 GST_FOURCC_ARGS (fourcc));
6755 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
6756 (_("This file is corrupt and cannot be played.")),
6757 ("Not enough data for an atom header, got only %u bytes", length));
6762 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
6763 (_("This file is corrupt and cannot be played.")),
6764 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
6765 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
6772 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
6776 guint32 child_fourcc;
6778 for (child = g_node_first_child (node); child;
6779 child = g_node_next_sibling (child)) {
6780 buffer = (guint8 *) child->data;
6782 child_fourcc = QT_FOURCC (buffer + 4);
6784 if (G_UNLIKELY (child_fourcc == fourcc)) {
6792 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
6793 GstByteReader * parser)
6797 guint32 child_fourcc, child_len;
6799 for (child = g_node_first_child (node); child;
6800 child = g_node_next_sibling (child)) {
6801 buffer = (guint8 *) child->data;
6803 child_len = QT_UINT32 (buffer);
6804 child_fourcc = QT_FOURCC (buffer + 4);
6806 if (G_UNLIKELY (child_fourcc == fourcc)) {
6807 if (G_UNLIKELY (child_len < (4 + 4)))
6809 /* FIXME: must verify if atom length < parent atom length */
6810 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
6818 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
6819 GstByteReader * parser)
6823 guint32 child_fourcc, child_len;
6825 for (child = g_node_next_sibling (node); child;
6826 child = g_node_next_sibling (child)) {
6827 buffer = (guint8 *) child->data;
6829 child_fourcc = QT_FOURCC (buffer + 4);
6831 if (child_fourcc == fourcc) {
6833 child_len = QT_UINT32 (buffer);
6834 if (G_UNLIKELY (child_len < (4 + 4)))
6836 /* FIXME: must verify if atom length < parent atom length */
6837 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
6846 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
6848 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
6852 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
6854 /* FIXME: This can only reliably work if demuxers have a
6855 * separate streaming thread per srcpad. This should be
6856 * done in a demuxer base class, which integrates parts
6859 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
6864 query = gst_query_new_allocation (stream->caps, FALSE);
6866 if (!gst_pad_peer_query (stream->pad, query)) {
6867 /* not a problem, just debug a little */
6868 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
6871 if (stream->allocator)
6872 gst_object_unref (stream->allocator);
6874 if (gst_query_get_n_allocation_params (query) > 0) {
6875 /* try the allocator */
6876 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
6878 stream->use_allocator = TRUE;
6880 stream->allocator = NULL;
6881 gst_allocation_params_init (&stream->params);
6882 stream->use_allocator = FALSE;
6884 gst_query_unref (query);
6889 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
6890 QtDemuxStream * stream)
6893 const gchar *selected_system;
6895 g_return_val_if_fail (qtdemux != NULL, FALSE);
6896 g_return_val_if_fail (stream != NULL, FALSE);
6897 g_return_val_if_fail (gst_caps_get_size (stream->caps) == 1, FALSE);
6899 if (stream->protection_scheme_type != FOURCC_cenc) {
6900 GST_ERROR_OBJECT (qtdemux, "unsupported protection scheme");
6903 if (qtdemux->protection_system_ids == NULL) {
6904 GST_ERROR_OBJECT (qtdemux, "stream is protected using cenc, but no "
6905 "cenc protection system information has been found");
6908 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
6909 selected_system = gst_protection_select_system ((const gchar **)
6910 qtdemux->protection_system_ids->pdata);
6911 g_ptr_array_remove_index (qtdemux->protection_system_ids,
6912 qtdemux->protection_system_ids->len - 1);
6913 if (!selected_system) {
6914 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
6915 "suitable decryptor element has been found");
6919 s = gst_caps_get_structure (stream->caps, 0);
6920 gst_structure_set (s,
6921 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
6922 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
6924 gst_structure_set_name (s, "application/x-cenc");
6929 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
6931 if (stream->subtype == FOURCC_vide) {
6932 /* fps is calculated base on the duration of the average framerate since
6933 * qt does not have a fixed framerate. */
6934 if ((stream->n_samples == 1) && (stream->first_duration == 0)) {
6939 if (stream->duration == 0 || stream->n_samples < 2) {
6940 stream->fps_n = stream->timescale;
6943 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
6944 /* stream->duration is guint64, timescale, n_samples are guint32 */
6945 GstClockTime avg_duration =
6946 gst_util_uint64_scale_round (stream->duration -
6947 stream->first_duration, GST_SECOND,
6948 (guint64) (stream->timescale) * (stream->n_samples - 1));
6950 GST_LOG_OBJECT (qtdemux,
6951 "Calculating avg sample duration based on stream duration %"
6953 " minus first sample %u, leaving %d samples gives %"
6954 GST_TIME_FORMAT, stream->duration, stream->first_duration,
6955 stream->n_samples - 1, GST_TIME_ARGS (avg_duration));
6957 gst_video_guess_framerate (avg_duration, &stream->fps_n,
6960 GST_DEBUG_OBJECT (qtdemux,
6961 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
6962 stream->timescale, stream->fps_n, stream->fps_d);
6966 stream->caps = gst_caps_make_writable (stream->caps);
6968 gst_caps_set_simple (stream->caps,
6969 "width", G_TYPE_INT, stream->width,
6970 "height", G_TYPE_INT, stream->height,
6971 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
6973 /* calculate pixel-aspect-ratio using display width and height */
6974 GST_DEBUG_OBJECT (qtdemux,
6975 "video size %dx%d, target display size %dx%d", stream->width,
6976 stream->height, stream->display_width, stream->display_height);
6977 /* qt file might have pasp atom */
6978 if (stream->par_w > 0 && stream->par_h > 0) {
6979 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
6980 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
6981 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
6982 } else if (stream->display_width > 0 && stream->display_height > 0 &&
6983 stream->width > 0 && stream->height > 0) {
6986 /* calculate the pixel aspect ratio using the display and pixel w/h */
6987 n = stream->display_width * stream->height;
6988 d = stream->display_height * stream->width;
6991 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
6994 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
6995 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
6998 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
6999 guint par_w = 1, par_h = 1;
7001 if (stream->par_w > 0 && stream->par_h > 0) {
7002 par_w = stream->par_w;
7003 par_h = stream->par_h;
7006 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
7007 stream->width, stream->height, par_w, par_h)) {
7008 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
7011 gst_caps_set_simple (stream->caps,
7012 "multiview-mode", G_TYPE_STRING,
7013 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
7014 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
7015 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
7020 else if (stream->subtype == FOURCC_soun) {
7022 stream->caps = gst_caps_make_writable (stream->caps);
7023 if (stream->rate > 0)
7024 gst_caps_set_simple (stream->caps,
7025 "rate", G_TYPE_INT, (int) stream->rate, NULL);
7026 if (stream->n_channels > 0)
7027 gst_caps_set_simple (stream->caps,
7028 "channels", G_TYPE_INT, stream->n_channels, NULL);
7029 if (stream->n_channels > 2) {
7030 /* FIXME: Need to parse the 'chan' atom to get channel layouts
7031 * correctly; this is just the minimum we can do - assume
7032 * we don't actually have any channel positions. */
7033 gst_caps_set_simple (stream->caps,
7034 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
7040 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
7041 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
7042 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
7043 gst_pad_set_active (stream->pad, TRUE);
7045 gst_pad_use_fixed_caps (stream->pad);
7047 if (stream->protected) {
7048 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
7049 GST_ERROR_OBJECT (qtdemux,
7050 "Failed to configure protected stream caps.");
7055 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
7056 if (stream->new_stream) {
7059 GstStreamFlags stream_flags;
7062 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
7065 if (gst_event_parse_group_id (event, &qtdemux->group_id))
7066 qtdemux->have_group_id = TRUE;
7068 qtdemux->have_group_id = FALSE;
7069 gst_event_unref (event);
7070 } else if (!qtdemux->have_group_id) {
7071 qtdemux->have_group_id = TRUE;
7072 qtdemux->group_id = gst_util_group_id_next ();
7075 stream->new_stream = FALSE;
7077 gst_pad_create_stream_id_printf (stream->pad,
7078 GST_ELEMENT_CAST (qtdemux), "%03u", stream->track_id);
7079 event = gst_event_new_stream_start (stream_id);
7080 if (qtdemux->have_group_id)
7081 gst_event_set_group_id (event, qtdemux->group_id);
7082 stream_flags = GST_STREAM_FLAG_NONE;
7083 if (stream->disabled)
7084 stream_flags |= GST_STREAM_FLAG_UNSELECT;
7086 stream_flags |= GST_STREAM_FLAG_SPARSE;
7087 gst_event_set_stream_flags (event, stream_flags);
7088 gst_pad_push_event (stream->pad, event);
7091 gst_pad_set_caps (stream->pad, stream->caps);
7092 stream->new_caps = FALSE;
7098 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
7099 QtDemuxStream * stream, GstTagList * list)
7101 /* consistent default for push based mode */
7102 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
7104 if (stream->subtype == FOURCC_vide) {
7105 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
7108 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
7111 gst_qtdemux_configure_stream (qtdemux, stream);
7112 qtdemux->n_video_streams++;
7113 } else if (stream->subtype == FOURCC_soun) {
7114 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
7117 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
7119 gst_qtdemux_configure_stream (qtdemux, stream);
7120 qtdemux->n_audio_streams++;
7121 } else if (stream->subtype == FOURCC_strm) {
7122 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
7123 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
7124 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
7125 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
7128 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
7130 gst_qtdemux_configure_stream (qtdemux, stream);
7131 qtdemux->n_sub_streams++;
7132 } else if (stream->caps) {
7133 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
7136 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
7138 gst_qtdemux_configure_stream (qtdemux, stream);
7139 qtdemux->n_video_streams++;
7141 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
7148 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
7149 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
7150 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
7151 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
7153 if (stream->pending_tags)
7154 gst_tag_list_unref (stream->pending_tags);
7155 stream->pending_tags = list;
7157 /* global tags go on each pad anyway */
7158 stream->send_global_tags = TRUE;
7159 /* send upstream GST_EVENT_PROTECTION events that were received before
7160 this source pad was created */
7161 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
7162 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
7166 gst_tag_list_unref (list);
7170 /* find next atom with @fourcc starting at @offset */
7171 static GstFlowReturn
7172 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
7173 guint64 * length, guint32 fourcc)
7179 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
7180 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
7186 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
7187 if (G_UNLIKELY (ret != GST_FLOW_OK))
7189 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
7192 gst_buffer_unref (buf);
7195 gst_buffer_map (buf, &map, GST_MAP_READ);
7196 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
7197 gst_buffer_unmap (buf, &map);
7198 gst_buffer_unref (buf);
7200 if (G_UNLIKELY (*length == 0)) {
7201 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
7202 ret = GST_FLOW_ERROR;
7206 if (lfourcc == fourcc) {
7207 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
7211 GST_LOG_OBJECT (qtdemux,
7212 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
7213 GST_FOURCC_ARGS (fourcc), *offset);
7222 /* might simply have had last one */
7223 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
7228 /* should only do something in pull mode */
7229 /* call with OBJECT lock */
7230 static GstFlowReturn
7231 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
7233 guint64 length, offset;
7234 GstBuffer *buf = NULL;
7235 GstFlowReturn ret = GST_FLOW_OK;
7236 GstFlowReturn res = GST_FLOW_OK;
7239 offset = qtdemux->moof_offset;
7240 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
7243 GST_DEBUG_OBJECT (qtdemux, "no next moof");
7244 return GST_FLOW_EOS;
7247 /* best not do pull etc with lock held */
7248 GST_OBJECT_UNLOCK (qtdemux);
7250 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
7251 if (ret != GST_FLOW_OK)
7254 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
7255 if (G_UNLIKELY (ret != GST_FLOW_OK))
7257 gst_buffer_map (buf, &map, GST_MAP_READ);
7258 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
7259 gst_buffer_unmap (buf, &map);
7260 gst_buffer_unref (buf);
7265 gst_buffer_unmap (buf, &map);
7266 gst_buffer_unref (buf);
7270 /* look for next moof */
7271 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
7272 if (G_UNLIKELY (ret != GST_FLOW_OK))
7276 GST_OBJECT_LOCK (qtdemux);
7278 qtdemux->moof_offset = offset;
7284 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
7286 res = GST_FLOW_ERROR;
7291 /* maybe upstream temporarily flushing */
7292 if (ret != GST_FLOW_FLUSHING) {
7293 GST_DEBUG_OBJECT (qtdemux, "no next moof");
7296 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
7297 /* resume at current position next time */
7304 /* initialise bytereaders for stbl sub-atoms */
7306 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
7308 stream->stbl_index = -1; /* no samples have yet been parsed */
7309 stream->sample_index = -1;
7311 /* time-to-sample atom */
7312 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
7315 /* copy atom data into a new buffer for later use */
7316 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
7318 /* skip version + flags */
7319 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
7320 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
7322 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
7324 /* make sure there's enough data */
7325 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
7326 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
7327 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
7328 stream->n_sample_times);
7329 if (!stream->n_sample_times)
7333 /* sync sample atom */
7334 stream->stps_present = FALSE;
7335 if ((stream->stss_present =
7336 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
7337 &stream->stss) ? TRUE : FALSE) == TRUE) {
7338 /* copy atom data into a new buffer for later use */
7339 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
7341 /* skip version + flags */
7342 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
7343 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
7346 if (stream->n_sample_syncs) {
7347 /* make sure there's enough data */
7348 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
7352 /* partial sync sample atom */
7353 if ((stream->stps_present =
7354 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
7355 &stream->stps) ? TRUE : FALSE) == TRUE) {
7356 /* copy atom data into a new buffer for later use */
7357 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
7359 /* skip version + flags */
7360 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
7361 !gst_byte_reader_get_uint32_be (&stream->stps,
7362 &stream->n_sample_partial_syncs))
7365 /* if there are no entries, the stss table contains the real
7367 if (stream->n_sample_partial_syncs) {
7368 /* make sure there's enough data */
7369 if (!qt_atom_parser_has_chunks (&stream->stps,
7370 stream->n_sample_partial_syncs, 4))
7377 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
7380 /* copy atom data into a new buffer for later use */
7381 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
7383 /* skip version + flags */
7384 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
7385 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
7388 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
7391 if (!stream->n_samples)
7394 /* sample-to-chunk atom */
7395 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
7398 /* copy atom data into a new buffer for later use */
7399 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
7401 /* skip version + flags */
7402 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
7403 !gst_byte_reader_get_uint32_be (&stream->stsc,
7404 &stream->n_samples_per_chunk))
7407 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
7408 stream->n_samples_per_chunk);
7410 /* make sure there's enough data */
7411 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
7417 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
7418 stream->co_size = sizeof (guint32);
7419 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
7421 stream->co_size = sizeof (guint64);
7425 /* copy atom data into a new buffer for later use */
7426 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
7428 /* skip version + flags */
7429 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
7432 /* chunks_are_samples == TRUE means treat chunks as samples */
7433 stream->chunks_are_samples = stream->sample_size && !stream->sampled;
7434 if (stream->chunks_are_samples) {
7435 /* treat chunks as samples */
7436 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
7439 /* skip number of entries */
7440 if (!gst_byte_reader_skip (&stream->stco, 4))
7443 /* make sure there are enough data in the stsz atom */
7444 if (!stream->sample_size) {
7445 /* different sizes for each sample */
7446 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
7451 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
7452 stream->n_samples, (guint) sizeof (QtDemuxSample),
7453 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
7455 if (stream->n_samples >=
7456 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
7457 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
7458 "be larger than %uMB (broken file?)", stream->n_samples,
7459 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
7463 g_assert (stream->samples == NULL);
7464 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
7465 if (!stream->samples) {
7466 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
7471 /* composition time-to-sample */
7472 if ((stream->ctts_present =
7473 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
7474 &stream->ctts) ? TRUE : FALSE) == TRUE) {
7475 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
7477 /* copy atom data into a new buffer for later use */
7478 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
7480 /* skip version + flags */
7481 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
7482 || !gst_byte_reader_get_uint32_be (&stream->ctts,
7483 &stream->n_composition_times))
7486 /* make sure there's enough data */
7487 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
7491 /* This is optional, if missing we iterate the ctts */
7492 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
7493 if (!gst_byte_reader_skip (&cslg, 1 + 3)
7494 || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
7495 g_free ((gpointer) cslg.data);
7499 gint32 cslg_least = 0;
7500 guint num_entries, pos;
7503 pos = gst_byte_reader_get_pos (&stream->ctts);
7504 num_entries = stream->n_composition_times;
7506 stream->cslg_shift = 0;
7508 for (i = 0; i < num_entries; i++) {
7511 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
7512 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
7514 if (offset < cslg_least)
7515 cslg_least = offset;
7519 stream->cslg_shift = ABS (cslg_least);
7521 stream->cslg_shift = 0;
7523 /* reset the reader so we can generate sample table */
7524 gst_byte_reader_set_pos (&stream->ctts, pos);
7527 /* Ensure the cslg_shift value is consistent so we can use it
7528 * unconditionnally to produce TS and Segment */
7529 stream->cslg_shift = 0;
7536 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7537 (_("This file is corrupt and cannot be played.")), (NULL));
7542 gst_qtdemux_stbl_free (stream);
7543 if (!qtdemux->fragmented) {
7544 /* not quite good */
7545 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
7548 /* may pick up samples elsewhere */
7554 /* collect samples from the next sample to be parsed up to sample @n for @stream
7555 * by reading the info from @stbl
7557 * This code can be executed from both the streaming thread and the seeking
7558 * thread so it takes the object lock to protect itself
7561 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
7564 QtDemuxSample *samples, *first, *cur, *last;
7565 guint32 n_samples_per_chunk;
7568 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
7569 GST_FOURCC_FORMAT ", pad %s", GST_FOURCC_ARGS (stream->fourcc),
7570 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
7572 n_samples = stream->n_samples;
7575 goto out_of_samples;
7577 GST_OBJECT_LOCK (qtdemux);
7578 if (n <= stream->stbl_index)
7579 goto already_parsed;
7581 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
7583 if (!stream->stsz.data) {
7584 /* so we already parsed and passed all the moov samples;
7585 * onto fragmented ones */
7586 g_assert (qtdemux->fragmented);
7590 /* pointer to the sample table */
7591 samples = stream->samples;
7593 /* starts from -1, moves to the next sample index to parse */
7594 stream->stbl_index++;
7596 /* keep track of the first and last sample to fill */
7597 first = &samples[stream->stbl_index];
7600 if (!stream->chunks_are_samples) {
7601 /* set the sample sizes */
7602 if (stream->sample_size == 0) {
7603 /* different sizes for each sample */
7604 for (cur = first; cur <= last; cur++) {
7605 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
7606 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
7607 (guint) (cur - samples), cur->size);
7610 /* samples have the same size */
7611 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
7612 for (cur = first; cur <= last; cur++)
7613 cur->size = stream->sample_size;
7617 n_samples_per_chunk = stream->n_samples_per_chunk;
7620 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
7623 if (stream->stsc_chunk_index >= stream->last_chunk
7624 || stream->stsc_chunk_index < stream->first_chunk) {
7625 stream->first_chunk =
7626 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
7627 stream->samples_per_chunk =
7628 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
7629 gst_byte_reader_skip_unchecked (&stream->stsc, 4);
7631 /* chunk numbers are counted from 1 it seems */
7632 if (G_UNLIKELY (stream->first_chunk == 0))
7635 --stream->first_chunk;
7637 /* the last chunk of each entry is calculated by taking the first chunk
7638 * of the next entry; except if there is no next, where we fake it with
7640 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
7641 stream->last_chunk = G_MAXUINT32;
7643 stream->last_chunk =
7644 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
7645 if (G_UNLIKELY (stream->last_chunk == 0))
7648 --stream->last_chunk;
7651 GST_LOG_OBJECT (qtdemux,
7652 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
7653 stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
7655 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
7658 if (stream->last_chunk != G_MAXUINT32) {
7659 if (!qt_atom_parser_peek_sub (&stream->stco,
7660 stream->first_chunk * stream->co_size,
7661 (stream->last_chunk - stream->first_chunk) * stream->co_size,
7666 stream->co_chunk = stream->stco;
7667 if (!gst_byte_reader_skip (&stream->co_chunk,
7668 stream->first_chunk * stream->co_size))
7672 stream->stsc_chunk_index = stream->first_chunk;
7675 last_chunk = stream->last_chunk;
7677 if (stream->chunks_are_samples) {
7678 cur = &samples[stream->stsc_chunk_index];
7680 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
7683 stream->stsc_chunk_index = j;
7688 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
7691 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
7692 "%" G_GUINT64_FORMAT, j, cur->offset);
7694 if (stream->samples_per_frame * stream->bytes_per_frame) {
7696 (stream->samples_per_chunk * stream->n_channels) /
7697 stream->samples_per_frame * stream->bytes_per_frame;
7699 cur->size = stream->samples_per_chunk;
7702 GST_DEBUG_OBJECT (qtdemux,
7703 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
7704 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
7705 stream->stco_sample_index)), cur->size);
7707 cur->timestamp = stream->stco_sample_index;
7708 cur->duration = stream->samples_per_chunk;
7709 cur->keyframe = TRUE;
7712 stream->stco_sample_index += stream->samples_per_chunk;
7714 stream->stsc_chunk_index = j;
7716 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
7717 guint32 samples_per_chunk;
7718 guint64 chunk_offset;
7720 if (!stream->stsc_sample_index
7721 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
7722 &stream->chunk_offset))
7725 samples_per_chunk = stream->samples_per_chunk;
7726 chunk_offset = stream->chunk_offset;
7728 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
7729 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
7730 G_GUINT64_FORMAT " and size %d",
7731 (guint) (cur - samples), chunk_offset, cur->size);
7733 cur->offset = chunk_offset;
7734 chunk_offset += cur->size;
7737 if (G_UNLIKELY (cur > last)) {
7739 stream->stsc_sample_index = k + 1;
7740 stream->chunk_offset = chunk_offset;
7741 stream->stsc_chunk_index = j;
7745 stream->stsc_sample_index = 0;
7747 stream->stsc_chunk_index = j;
7749 stream->stsc_index++;
7752 if (stream->chunks_are_samples)
7756 guint32 n_sample_times;
7758 n_sample_times = stream->n_sample_times;
7761 for (i = stream->stts_index; i < n_sample_times; i++) {
7762 guint32 stts_samples;
7763 gint32 stts_duration;
7766 if (stream->stts_sample_index >= stream->stts_samples
7767 || !stream->stts_sample_index) {
7769 stream->stts_samples =
7770 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
7771 stream->stts_duration =
7772 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
7774 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
7775 i, stream->stts_samples, stream->stts_duration);
7777 stream->stts_sample_index = 0;
7780 stts_samples = stream->stts_samples;
7781 stts_duration = stream->stts_duration;
7782 stts_time = stream->stts_time;
7784 for (j = stream->stts_sample_index; j < stts_samples; j++) {
7785 GST_DEBUG_OBJECT (qtdemux,
7786 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
7787 (guint) (cur - samples), j,
7788 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
7790 cur->timestamp = stts_time;
7791 cur->duration = stts_duration;
7793 /* avoid 32-bit wrap-around,
7794 * but still mind possible 'negative' duration */
7795 stts_time += (gint64) stts_duration;
7798 if (G_UNLIKELY (cur > last)) {
7800 stream->stts_time = stts_time;
7801 stream->stts_sample_index = j + 1;
7805 stream->stts_sample_index = 0;
7806 stream->stts_time = stts_time;
7807 stream->stts_index++;
7809 /* fill up empty timestamps with the last timestamp, this can happen when
7810 * the last samples do not decode and so we don't have timestamps for them.
7811 * We however look at the last timestamp to estimate the track length so we
7812 * need something in here. */
7813 for (; cur < last; cur++) {
7814 GST_DEBUG_OBJECT (qtdemux,
7815 "fill sample %d: timestamp %" GST_TIME_FORMAT,
7816 (guint) (cur - samples),
7817 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
7818 cur->timestamp = stream->stts_time;
7824 /* sample sync, can be NULL */
7825 if (stream->stss_present == TRUE) {
7826 guint32 n_sample_syncs;
7828 n_sample_syncs = stream->n_sample_syncs;
7830 if (!n_sample_syncs) {
7831 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
7832 stream->all_keyframe = TRUE;
7834 for (i = stream->stss_index; i < n_sample_syncs; i++) {
7835 /* note that the first sample is index 1, not 0 */
7838 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
7840 if (G_LIKELY (index > 0 && index <= n_samples)) {
7842 samples[index].keyframe = TRUE;
7843 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
7844 /* and exit if we have enough samples */
7845 if (G_UNLIKELY (index >= n)) {
7852 stream->stss_index = i;
7855 /* stps marks partial sync frames like open GOP I-Frames */
7856 if (stream->stps_present == TRUE) {
7857 guint32 n_sample_partial_syncs;
7859 n_sample_partial_syncs = stream->n_sample_partial_syncs;
7861 /* if there are no entries, the stss table contains the real
7863 if (n_sample_partial_syncs) {
7864 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
7865 /* note that the first sample is index 1, not 0 */
7868 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
7870 if (G_LIKELY (index > 0 && index <= n_samples)) {
7872 samples[index].keyframe = TRUE;
7873 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
7874 /* and exit if we have enough samples */
7875 if (G_UNLIKELY (index >= n)) {
7882 stream->stps_index = i;
7886 /* no stss, all samples are keyframes */
7887 stream->all_keyframe = TRUE;
7888 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
7893 /* composition time to sample */
7894 if (stream->ctts_present == TRUE) {
7895 guint32 n_composition_times;
7897 gint32 ctts_soffset;
7899 /* Fill in the pts_offsets */
7901 n_composition_times = stream->n_composition_times;
7903 for (i = stream->ctts_index; i < n_composition_times; i++) {
7904 if (stream->ctts_sample_index >= stream->ctts_count
7905 || !stream->ctts_sample_index) {
7906 stream->ctts_count =
7907 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
7908 stream->ctts_soffset =
7909 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
7910 stream->ctts_sample_index = 0;
7913 ctts_count = stream->ctts_count;
7914 ctts_soffset = stream->ctts_soffset;
7916 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
7917 cur->pts_offset = ctts_soffset;
7920 if (G_UNLIKELY (cur > last)) {
7922 stream->ctts_sample_index = j + 1;
7926 stream->ctts_sample_index = 0;
7927 stream->ctts_index++;
7931 stream->stbl_index = n;
7932 /* if index has been completely parsed, free data that is no-longer needed */
7933 if (n + 1 == stream->n_samples) {
7934 gst_qtdemux_stbl_free (stream);
7935 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
7936 if (qtdemux->pullbased) {
7937 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
7938 while (n + 1 == stream->n_samples)
7939 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
7943 GST_OBJECT_UNLOCK (qtdemux);
7950 GST_LOG_OBJECT (qtdemux,
7951 "Tried to parse up to sample %u but this sample has already been parsed",
7953 /* if fragmented, there may be more */
7954 if (qtdemux->fragmented && n == stream->stbl_index)
7956 GST_OBJECT_UNLOCK (qtdemux);
7962 GST_LOG_OBJECT (qtdemux,
7963 "Tried to parse up to sample %u but there are only %u samples", n + 1,
7965 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7966 (_("This file is corrupt and cannot be played.")), (NULL));
7971 GST_OBJECT_UNLOCK (qtdemux);
7972 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7973 (_("This file is corrupt and cannot be played.")), (NULL));
7978 /* collect all segment info for @stream.
7981 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
7985 /* accept edts if they contain gaps at start and there is only
7986 * one media segment */
7987 gboolean allow_pushbased_edts = TRUE;
7988 gint media_segments_count = 0;
7990 /* parse and prepare segment info from the edit list */
7991 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
7992 stream->n_segments = 0;
7993 stream->segments = NULL;
7994 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
8002 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
8003 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
8006 buffer = elst->data;
8008 n_segments = QT_UINT32 (buffer + 12);
8010 /* we might allocate a bit too much, at least allocate 1 segment */
8011 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
8013 /* segments always start from 0 */
8017 for (i = 0; i < n_segments; i++) {
8020 QtDemuxSegment *segment;
8023 media_time = QT_UINT32 (buffer + 20 + i * 12);
8024 duration = QT_UINT32 (buffer + 16 + i * 12);
8026 segment = &stream->segments[count++];
8028 /* time and duration expressed in global timescale */
8029 segment->time = stime;
8030 /* add non scaled values so we don't cause roundoff errors */
8032 stime = QTTIME_TO_GSTTIME (qtdemux, time);
8033 segment->stop_time = stime;
8034 segment->duration = stime - segment->time;
8036 segment->trak_media_start = media_time;
8037 /* media_time expressed in stream timescale */
8038 if (media_time != G_MAXUINT32) {
8039 segment->media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
8040 segment->media_stop = segment->media_start + segment->duration;
8041 media_segments_count++;
8043 segment->media_start = GST_CLOCK_TIME_NONE;
8044 segment->media_stop = GST_CLOCK_TIME_NONE;
8046 rate_int = GST_READ_UINT32_BE (buffer + 24 + i * 12);
8048 if (rate_int <= 1) {
8049 /* 0 is not allowed, some programs write 1 instead of the floating point
8051 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
8055 segment->rate = rate_int / 65536.0;
8058 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
8059 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
8060 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
8061 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
8062 i, GST_TIME_ARGS (segment->time),
8063 GST_TIME_ARGS (segment->duration),
8064 GST_TIME_ARGS (segment->media_start), media_time,
8065 GST_TIME_ARGS (segment->media_stop),
8066 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
8068 if (segment->stop_time > qtdemux->segment.stop) {
8069 GST_WARNING_OBJECT (qtdemux, "Segment %d "
8070 " extends to %" GST_TIME_FORMAT
8071 " past the end of the file duration %" GST_TIME_FORMAT
8072 " it will be truncated", i, GST_TIME_ARGS (segment->stop_time),
8073 GST_TIME_ARGS (qtdemux->segment.stop));
8074 qtdemux->segment.stop = segment->stop_time;
8077 GST_DEBUG_OBJECT (qtdemux, "found %d segments", count);
8078 stream->n_segments = count;
8079 if (media_segments_count != 1)
8080 allow_pushbased_edts = FALSE;
8084 /* push based does not handle segments, so act accordingly here,
8085 * and warn if applicable */
8086 if (!qtdemux->pullbased && !allow_pushbased_edts) {
8087 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
8088 /* remove and use default one below, we stream like it anyway */
8089 g_free (stream->segments);
8090 stream->segments = NULL;
8091 stream->n_segments = 0;
8094 /* no segments, create one to play the complete trak */
8095 if (stream->n_segments == 0) {
8096 GstClockTime stream_duration =
8097 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
8099 if (stream->segments == NULL)
8100 stream->segments = g_new (QtDemuxSegment, 1);
8102 /* represent unknown our way */
8103 if (stream_duration == 0)
8104 stream_duration = GST_CLOCK_TIME_NONE;
8106 stream->segments[0].time = 0;
8107 stream->segments[0].stop_time = stream_duration;
8108 stream->segments[0].duration = stream_duration;
8109 stream->segments[0].media_start = 0;
8110 stream->segments[0].media_stop = stream_duration;
8111 stream->segments[0].rate = 1.0;
8112 stream->segments[0].trak_media_start = 0;
8114 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
8115 GST_TIME_ARGS (stream_duration));
8116 stream->n_segments = 1;
8117 stream->dummy_segment = TRUE;
8119 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
8125 * Parses the stsd atom of a svq3 trak looking for
8126 * the SMI and gama atoms.
8129 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
8130 guint8 ** gamma, GstBuffer ** seqh)
8132 guint8 *_gamma = NULL;
8133 GstBuffer *_seqh = NULL;
8134 guint8 *stsd_data = stsd->data;
8135 guint32 length = QT_UINT32 (stsd_data);
8139 GST_WARNING_OBJECT (qtdemux, "stsd too short");
8145 version = QT_UINT16 (stsd_data);
8150 while (length > 8) {
8151 guint32 fourcc, size;
8153 size = QT_UINT32 (stsd_data);
8154 fourcc = QT_FOURCC (stsd_data + 4);
8155 data = stsd_data + 8;
8158 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
8159 "svq3 atom parsing");
8168 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
8169 " for gama atom, expected 12", size);
8174 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
8176 if (_seqh != NULL) {
8177 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
8178 " found, ignoring");
8180 seqh_size = QT_UINT32 (data + 4);
8181 if (seqh_size > 0) {
8182 _seqh = gst_buffer_new_and_alloc (seqh_size);
8183 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
8190 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
8191 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
8195 if (size <= length) {
8201 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
8204 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
8205 G_GUINT16_FORMAT, version);
8216 gst_buffer_unref (_seqh);
8221 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
8228 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
8229 * atom that might contain a 'data' atom with the rtsp uri.
8230 * This case was reported in bug #597497, some info about
8231 * the hndl atom can be found in TN1195
8233 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
8234 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
8237 guint32 dref_num_entries = 0;
8238 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
8239 gst_byte_reader_skip (&dref, 4) &&
8240 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
8243 /* search dref entries for hndl atom */
8244 for (i = 0; i < dref_num_entries; i++) {
8245 guint32 size = 0, type;
8246 guint8 string_len = 0;
8247 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
8248 qt_atom_parser_get_fourcc (&dref, &type)) {
8249 if (type == FOURCC_hndl) {
8250 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
8252 /* skip data reference handle bytes and the
8253 * following pascal string and some extra 4
8254 * bytes I have no idea what are */
8255 if (!gst_byte_reader_skip (&dref, 4) ||
8256 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
8257 !gst_byte_reader_skip (&dref, string_len + 4)) {
8258 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
8262 /* iterate over the atoms to find the data atom */
8263 while (gst_byte_reader_get_remaining (&dref) >= 8) {
8267 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
8268 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
8269 if (atom_type == FOURCC_data) {
8270 const guint8 *uri_aux = NULL;
8272 /* found the data atom that might contain the rtsp uri */
8273 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
8274 "hndl atom, interpreting it as an URI");
8275 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
8277 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
8278 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
8280 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
8281 "didn't contain a rtsp address");
8283 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
8288 /* skipping to the next entry */
8289 if (!gst_byte_reader_skip (&dref, atom_size - 8))
8292 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
8299 /* skip to the next entry */
8300 if (!gst_byte_reader_skip (&dref, size - 8))
8303 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
8306 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
8312 #define AMR_NB_ALL_MODES 0x81ff
8313 #define AMR_WB_ALL_MODES 0x83ff
8315 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
8317 /* The 'damr' atom is of the form:
8319 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
8320 * 32 b 8 b 16 b 8 b 8 b
8322 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
8323 * represents the highest mode used in the stream (and thus the maximum
8324 * bitrate), with a couple of special cases as seen below.
8327 /* Map of frame type ID -> bitrate */
8328 static const guint nb_bitrates[] = {
8329 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
8331 static const guint wb_bitrates[] = {
8332 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
8338 gst_buffer_map (buf, &map, GST_MAP_READ);
8340 if (map.size != 0x11) {
8341 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
8345 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
8346 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
8347 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
8351 mode_set = QT_UINT16 (map.data + 13);
8353 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
8354 max_mode = 7 + (wb ? 1 : 0);
8356 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
8357 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
8359 if (max_mode == -1) {
8360 GST_DEBUG ("No mode indication was found (mode set) = %x",
8365 gst_buffer_unmap (buf, &map);
8366 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
8369 gst_buffer_unmap (buf, &map);
8374 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
8375 GstByteReader * reader, guint32 * matrix, const gchar * atom)
8378 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
8384 if (gst_byte_reader_get_remaining (reader) < 36)
8387 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
8388 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
8389 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
8390 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
8391 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
8392 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
8393 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
8394 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
8395 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
8397 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
8398 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
8399 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
8401 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
8402 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
8404 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
8405 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
8412 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
8413 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
8420 * This macro will only compare value abdegh, it expects cfi to have already
8423 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
8424 (m)[3] == (d << 16) && (m)[4] == (e << 16))
8426 /* only handle the cases where the last column has standard values */
8427 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
8428 const gchar *rotation_tag = NULL;
8430 /* no rotation needed */
8431 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
8433 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
8434 rotation_tag = "rotate-90";
8435 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
8436 rotation_tag = "rotate-180";
8437 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
8438 rotation_tag = "rotate-270";
8440 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
8443 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
8445 if (rotation_tag != NULL) {
8446 if (*taglist == NULL)
8447 *taglist = gst_tag_list_new_empty ();
8448 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
8449 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
8452 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
8456 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
8457 * protected streams (sinf, frma, schm and schi); if the protection scheme is
8458 * Common Encryption (cenc), the function will also parse the tenc box (defined
8459 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
8460 * (typically an enc[v|a|t|s] sample entry); the function will set
8461 * @original_fmt to the fourcc of the original unencrypted stream format.
8462 * Returns TRUE if successful; FALSE otherwise. */
8464 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
8465 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
8472 g_return_val_if_fail (qtdemux != NULL, FALSE);
8473 g_return_val_if_fail (stream != NULL, FALSE);
8474 g_return_val_if_fail (container != NULL, FALSE);
8475 g_return_val_if_fail (original_fmt != NULL, FALSE);
8477 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
8478 if (G_UNLIKELY (!sinf)) {
8479 if (stream->protection_scheme_type == FOURCC_cenc) {
8480 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
8481 "mandatory for Common Encryption");
8487 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
8488 if (G_UNLIKELY (!frma)) {
8489 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
8493 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
8494 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
8495 GST_FOURCC_ARGS (*original_fmt));
8497 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
8499 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
8502 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
8503 stream->protection_scheme_version =
8504 QT_UINT32 ((const guint8 *) schm->data + 16);
8506 GST_DEBUG_OBJECT (qtdemux,
8507 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
8508 "protection_scheme_version: %#010x",
8509 GST_FOURCC_ARGS (stream->protection_scheme_type),
8510 stream->protection_scheme_version);
8512 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
8514 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
8517 if (stream->protection_scheme_type == FOURCC_cenc) {
8518 QtDemuxCencSampleSetInfo *info;
8520 const guint8 *tenc_data;
8521 guint32 isEncrypted;
8523 const guint8 *default_kid;
8526 if (G_UNLIKELY (!stream->protection_scheme_info))
8527 stream->protection_scheme_info =
8528 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
8530 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
8532 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
8534 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
8535 "which is mandatory for Common Encryption");
8538 tenc_data = (const guint8 *) tenc->data + 12;
8539 isEncrypted = QT_UINT24 (tenc_data);
8540 iv_size = QT_UINT8 (tenc_data + 3);
8541 default_kid = (tenc_data + 4);
8542 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
8543 gst_buffer_fill (kid_buf, 0, default_kid, 16);
8544 if (info->default_properties)
8545 gst_structure_free (info->default_properties);
8546 info->default_properties =
8547 gst_structure_new ("application/x-cenc",
8548 "iv_size", G_TYPE_UINT, iv_size,
8549 "encrypted", G_TYPE_BOOLEAN, (isEncrypted == 1),
8550 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
8551 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
8552 "is_encrypted=%u, iv_size=%u", isEncrypted, iv_size);
8553 gst_buffer_unref (kid_buf);
8559 * With each track we associate a new QtDemuxStream that contains all the info
8561 * traks that do not decode to something (like strm traks) will not have a pad.
8564 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
8583 QtDemuxStream *stream = NULL;
8584 gboolean new_stream = FALSE;
8585 gchar *codec = NULL;
8586 const guint8 *stsd_data;
8587 guint16 lang_code; /* quicktime lang code or packed iso code */
8589 guint32 tkhd_flags = 0;
8590 guint8 tkhd_version = 0;
8592 guint value_size, stsd_len, len;
8596 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
8598 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
8599 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
8600 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
8603 /* pick between 64 or 32 bits */
8604 value_size = tkhd_version == 1 ? 8 : 4;
8605 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
8606 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
8609 if (!qtdemux->got_moov) {
8610 if (qtdemux_find_stream (qtdemux, track_id))
8611 goto existing_stream;
8612 stream = _create_stream ();
8613 stream->track_id = track_id;
8616 stream = qtdemux_find_stream (qtdemux, track_id);
8618 GST_WARNING_OBJECT (qtdemux, "Stream not found, going to ignore it");
8622 /* flush samples data from this track from previous moov */
8623 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
8624 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
8626 /* need defaults for fragments */
8627 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
8629 if (stream->pending_tags == NULL)
8630 stream->pending_tags = gst_tag_list_new_empty ();
8632 if ((tkhd_flags & 1) == 0)
8633 stream->disabled = TRUE;
8635 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
8636 tkhd_version, tkhd_flags, stream->track_id);
8638 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
8641 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
8642 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
8643 if (qtdemux->major_brand != FOURCC_mjp2 ||
8644 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
8648 len = QT_UINT32 ((guint8 *) mdhd->data);
8649 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
8650 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
8651 if (version == 0x01000000) {
8654 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
8655 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
8656 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
8660 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
8661 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
8662 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
8665 if (lang_code < 0x400) {
8666 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
8667 } else if (lang_code == 0x7fff) {
8668 stream->lang_id[0] = 0; /* unspecified */
8670 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
8671 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
8672 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
8673 stream->lang_id[3] = 0;
8676 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
8678 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
8680 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
8681 lang_code, stream->lang_id);
8683 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
8686 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
8687 /* chapters track reference */
8688 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
8690 gsize length = GST_READ_UINT32_BE (chap->data);
8691 if (qtdemux->chapters_track_id)
8692 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
8695 qtdemux->chapters_track_id =
8696 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
8701 /* fragmented files may have bogus duration in moov */
8702 if (!qtdemux->fragmented &&
8703 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
8704 guint64 tdur1, tdur2;
8706 /* don't overflow */
8707 tdur1 = stream->timescale * (guint64) qtdemux->duration;
8708 tdur2 = qtdemux->timescale * (guint64) stream->duration;
8711 * some of those trailers, nowadays, have prologue images that are
8712 * themselves vide tracks as well. I haven't really found a way to
8713 * identify those yet, except for just looking at their duration. */
8714 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
8715 GST_WARNING_OBJECT (qtdemux,
8716 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
8717 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
8718 "found, assuming preview image or something; skipping track",
8719 stream->duration, stream->timescale, qtdemux->duration,
8720 qtdemux->timescale);
8722 gst_qtdemux_stream_free (qtdemux, stream);
8727 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
8730 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
8731 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
8733 len = QT_UINT32 ((guint8 *) hdlr->data);
8735 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
8736 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
8737 GST_FOURCC_ARGS (stream->subtype));
8739 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
8742 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
8745 /*parse svmi header if existing */
8746 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
8748 len = QT_UINT32 ((guint8 *) svmi->data);
8749 version = QT_UINT32 ((guint8 *) svmi->data + 8);
8751 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
8752 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
8753 guint8 frame_type, frame_layout;
8755 /* MPEG-A stereo video */
8756 if (qtdemux->major_brand == FOURCC_ss02)
8757 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
8759 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
8760 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
8761 switch (frame_type) {
8763 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
8766 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
8769 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
8772 /* mode 3 is primary/secondary view sequence, ie
8773 * left/right views in separate tracks. See section 7.2
8774 * of ISO/IEC 23000-11:2009 */
8775 GST_FIXME_OBJECT (qtdemux,
8776 "Implement stereo video in separate streams");
8779 if ((frame_layout & 0x1) == 0)
8780 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
8782 GST_LOG_OBJECT (qtdemux,
8783 "StereoVideo: composition type: %u, is_left_first: %u",
8784 frame_type, frame_layout);
8785 stream->multiview_mode = mode;
8786 stream->multiview_flags = flags;
8791 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
8793 stsd_data = (const guint8 *) stsd->data;
8795 /* stsd should at least have one entry */
8796 stsd_len = QT_UINT32 (stsd_data);
8797 if (stsd_len < 24) {
8798 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
8799 if (stream->subtype == FOURCC_vivo) {
8801 gst_qtdemux_stream_free (qtdemux, stream);
8808 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
8810 /* and that entry should fit within stsd */
8811 len = QT_UINT32 (stsd_data + 16);
8812 if (len > stsd_len + 16)
8815 stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
8816 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
8817 GST_FOURCC_ARGS (stream->fourcc));
8818 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
8820 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
8821 goto error_encrypted;
8823 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
8824 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
8825 stream->protected = TRUE;
8826 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
8827 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
8830 if (stream->subtype == FOURCC_vide) {
8831 guint32 w = 0, h = 0;
8833 gint depth, palette_size, palette_count;
8835 guint32 *palette_data = NULL;
8837 stream->sampled = TRUE;
8839 /* version 1 uses some 64-bit ints */
8840 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
8843 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
8846 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
8847 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
8850 stream->display_width = w >> 16;
8851 stream->display_height = h >> 16;
8853 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
8854 &stream->pending_tags);
8860 stream->width = QT_UINT16 (stsd_data + offset + 32);
8861 stream->height = QT_UINT16 (stsd_data + offset + 34);
8862 stream->fps_n = 0; /* this is filled in later */
8863 stream->fps_d = 0; /* this is filled in later */
8864 stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
8865 stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
8867 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
8868 stream->width, stream->height, stream->bits_per_sample,
8869 stream->color_table_id);
8871 depth = stream->bits_per_sample;
8873 /* more than 32 bits means grayscale */
8874 gray = (depth > 32);
8875 /* low 32 bits specify the depth */
8878 /* different number of palette entries is determined by depth. */
8880 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
8881 palette_count = (1 << depth);
8882 palette_size = palette_count * 4;
8884 if (stream->color_table_id) {
8885 switch (palette_count) {
8889 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
8892 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
8896 palette_data = g_memdup (ff_qt_grayscale_palette_16, palette_size);
8898 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
8902 palette_data = g_memdup (ff_qt_grayscale_palette_256, palette_size);
8904 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
8907 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
8908 (_("The video in this file might not play correctly.")),
8909 ("unsupported palette depth %d", depth));
8913 gint i, j, start, end;
8919 start = QT_UINT32 (stsd_data + offset + 86);
8920 palette_count = QT_UINT16 (stsd_data + offset + 90);
8921 end = QT_UINT16 (stsd_data + offset + 92);
8923 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
8924 start, end, palette_count);
8931 if (len < 94 + (end - start) * 8)
8934 /* palette is always the same size */
8935 palette_data = g_malloc0 (256 * 4);
8936 palette_size = 256 * 4;
8938 for (j = 0, i = start; i <= end; j++, i++) {
8941 a = QT_UINT16 (stsd_data + offset + 94 + (j * 8));
8942 r = QT_UINT16 (stsd_data + offset + 96 + (j * 8));
8943 g = QT_UINT16 (stsd_data + offset + 98 + (j * 8));
8944 b = QT_UINT16 (stsd_data + offset + 100 + (j * 8));
8946 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
8947 (g & 0xff00) | (b >> 8);
8952 gst_caps_unref (stream->caps);
8955 qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
8956 if (G_UNLIKELY (!stream->caps)) {
8957 g_free (palette_data);
8958 goto unknown_stream;
8962 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
8963 GST_TAG_VIDEO_CODEC, codec, NULL);
8972 if (stream->rgb8_palette)
8973 gst_memory_unref (stream->rgb8_palette);
8974 stream->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
8975 palette_data, palette_size, 0, palette_size, palette_data, g_free);
8977 s = gst_caps_get_structure (stream->caps, 0);
8979 /* non-raw video has a palette_data property. raw video has the palette as
8980 * an extra plane that we append to the output buffers before we push
8982 if (!gst_structure_has_name (s, "video/x-raw")) {
8985 palette = gst_buffer_new ();
8986 gst_buffer_append_memory (palette, stream->rgb8_palette);
8987 stream->rgb8_palette = NULL;
8989 gst_caps_set_simple (stream->caps, "palette_data",
8990 GST_TYPE_BUFFER, palette, NULL);
8991 gst_buffer_unref (palette);
8993 } else if (palette_count != 0) {
8994 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
8995 (NULL), ("Unsupported palette depth %d", depth));
8998 GST_LOG_OBJECT (qtdemux, "frame count: %u",
8999 QT_UINT16 (stsd_data + offset + 48));
9003 /* pick 'the' stsd child */
9004 if (!stream->protected)
9005 mp4v = qtdemux_tree_get_child_by_type (stsd, fourcc);
9007 mp4v = qtdemux_tree_get_child_by_type (stsd, FOURCC_encv);
9010 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
9011 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
9015 const guint8 *pasp_data = (const guint8 *) pasp->data;
9017 stream->par_w = QT_UINT32 (pasp_data + 8);
9018 stream->par_h = QT_UINT32 (pasp_data + 12);
9025 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
9032 gint len = QT_UINT32 (stsd_data) - 0x66;
9033 const guint8 *avc_data = stsd_data + 0x66;
9036 while (len >= 0x8) {
9039 if (QT_UINT32 (avc_data) <= len)
9040 size = QT_UINT32 (avc_data) - 0x8;
9045 /* No real data, so break out */
9048 switch (QT_FOURCC (avc_data + 0x4)) {
9051 /* parse, if found */
9054 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
9056 /* First 4 bytes are the length of the atom, the next 4 bytes
9057 * are the fourcc, the next 1 byte is the version, and the
9058 * subsequent bytes are profile_tier_level structure like data. */
9059 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
9060 avc_data + 8 + 1, size - 1);
9061 buf = gst_buffer_new_and_alloc (size);
9062 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
9063 gst_caps_set_simple (stream->caps,
9064 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9065 gst_buffer_unref (buf);
9073 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
9075 /* First 4 bytes are the length of the atom, the next 4 bytes
9076 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
9077 * next 1 byte is the version, and the
9078 * subsequent bytes are sequence parameter set like data. */
9080 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
9082 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
9083 avc_data + 8 + 40 + 1, size - 1);
9085 buf = gst_buffer_new_and_alloc (size);
9086 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
9087 gst_caps_set_simple (stream->caps,
9088 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9089 gst_buffer_unref (buf);
9095 guint avg_bitrate, max_bitrate;
9097 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
9101 max_bitrate = QT_UINT32 (avc_data + 0xc);
9102 avg_bitrate = QT_UINT32 (avc_data + 0x10);
9104 if (!max_bitrate && !avg_bitrate)
9107 /* Some muxers seem to swap the average and maximum bitrates
9108 * (I'm looking at you, YouTube), so we swap for sanity. */
9109 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
9110 guint temp = avg_bitrate;
9112 avg_bitrate = max_bitrate;
9116 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
9117 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9118 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
9120 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
9121 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9122 GST_TAG_BITRATE, avg_bitrate, NULL);
9133 avc_data += size + 8;
9142 gint len = QT_UINT32 (stsd_data) - 0x66;
9143 const guint8 *hevc_data = stsd_data + 0x66;
9146 while (len >= 0x8) {
9149 if (QT_UINT32 (hevc_data) <= len)
9150 size = QT_UINT32 (hevc_data) - 0x8;
9155 /* No real data, so break out */
9158 switch (QT_FOURCC (hevc_data + 0x4)) {
9161 /* parse, if found */
9164 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
9166 /* First 4 bytes are the length of the atom, the next 4 bytes
9167 * are the fourcc, the next 1 byte is the version, and the
9168 * subsequent bytes are sequence parameter set like data. */
9169 gst_codec_utils_h265_caps_set_level_tier_and_profile
9170 (stream->caps, hevc_data + 8 + 1, size - 1);
9172 buf = gst_buffer_new_and_alloc (size);
9173 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
9174 gst_caps_set_simple (stream->caps,
9175 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9176 gst_buffer_unref (buf);
9183 hevc_data += size + 8;
9194 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
9195 GST_FOURCC_ARGS (fourcc));
9197 /* codec data might be in glbl extension atom */
9199 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
9205 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
9207 len = QT_UINT32 (data);
9210 buf = gst_buffer_new_and_alloc (len);
9211 gst_buffer_fill (buf, 0, data + 8, len);
9212 gst_caps_set_simple (stream->caps,
9213 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9214 gst_buffer_unref (buf);
9221 /* see annex I of the jpeg2000 spec */
9222 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
9224 const gchar *colorspace = NULL;
9226 guint32 ncomp_map = 0;
9227 gint32 *comp_map = NULL;
9228 guint32 nchan_def = 0;
9229 gint32 *chan_def = NULL;
9231 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
9232 /* some required atoms */
9233 mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
9236 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
9240 /* number of components; redundant with info in codestream, but useful
9242 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
9243 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
9245 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
9247 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
9250 GST_DEBUG_OBJECT (qtdemux, "found colr");
9251 /* extract colour space info */
9252 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
9253 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
9255 colorspace = "sRGB";
9258 colorspace = "GRAY";
9261 colorspace = "sYUV";
9269 /* colr is required, and only values 16, 17, and 18 are specified,
9270 so error if we have no colorspace */
9273 /* extract component mapping */
9274 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
9276 guint32 cmap_len = 0;
9278 cmap_len = QT_UINT32 (cmap->data);
9279 if (cmap_len >= 8) {
9280 /* normal box, subtract off header */
9282 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
9283 if (cmap_len % 4 == 0) {
9284 ncomp_map = (cmap_len / 4);
9285 comp_map = g_new0 (gint32, ncomp_map);
9286 for (i = 0; i < ncomp_map; i++) {
9289 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
9290 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
9291 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
9292 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
9297 /* extract channel definitions */
9298 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
9300 guint32 cdef_len = 0;
9302 cdef_len = QT_UINT32 (cdef->data);
9303 if (cdef_len >= 10) {
9304 /* normal box, subtract off header and len */
9306 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
9307 if (cdef_len % 6 == 0) {
9308 nchan_def = (cdef_len / 6);
9309 chan_def = g_new0 (gint32, nchan_def);
9310 for (i = 0; i < nchan_def; i++)
9312 for (i = 0; i < nchan_def; i++) {
9313 guint16 cn, typ, asoc;
9314 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
9315 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
9316 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
9317 if (cn < nchan_def) {
9320 chan_def[cn] = asoc;
9323 chan_def[cn] = 0; /* alpha */
9326 chan_def[cn] = -typ;
9334 gst_caps_set_simple (stream->caps,
9335 "num-components", G_TYPE_INT, ncomp, NULL);
9336 gst_caps_set_simple (stream->caps,
9337 "colorspace", G_TYPE_STRING, colorspace, NULL);
9340 GValue arr = { 0, };
9341 GValue elt = { 0, };
9343 g_value_init (&arr, GST_TYPE_ARRAY);
9344 g_value_init (&elt, G_TYPE_INT);
9345 for (i = 0; i < ncomp_map; i++) {
9346 g_value_set_int (&elt, comp_map[i]);
9347 gst_value_array_append_value (&arr, &elt);
9349 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
9350 "component-map", &arr);
9351 g_value_unset (&elt);
9352 g_value_unset (&arr);
9357 GValue arr = { 0, };
9358 GValue elt = { 0, };
9360 g_value_init (&arr, GST_TYPE_ARRAY);
9361 g_value_init (&elt, G_TYPE_INT);
9362 for (i = 0; i < nchan_def; i++) {
9363 g_value_set_int (&elt, chan_def[i]);
9364 gst_value_array_append_value (&arr, &elt);
9366 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
9367 "channel-definitions", &arr);
9368 g_value_unset (&elt);
9369 g_value_unset (&arr);
9373 /* some optional atoms */
9374 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
9375 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
9377 /* indicate possible fields in caps */
9379 data = (guint8 *) field->data + 8;
9381 gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
9382 (gint) * data, NULL);
9384 /* add codec_data if provided */
9389 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
9390 data = prefix->data;
9391 len = QT_UINT32 (data);
9394 buf = gst_buffer_new_and_alloc (len);
9395 gst_buffer_fill (buf, 0, data + 8, len);
9396 gst_caps_set_simple (stream->caps,
9397 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9398 gst_buffer_unref (buf);
9407 GstBuffer *seqh = NULL;
9408 guint8 *gamma_data = NULL;
9409 gint len = QT_UINT32 (stsd_data);
9411 qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
9413 gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
9414 QT_FP32 (gamma_data), NULL);
9417 /* sorry for the bad name, but we don't know what this is, other
9418 * than its own fourcc */
9419 gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
9423 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
9424 buf = gst_buffer_new_and_alloc (len);
9425 gst_buffer_fill (buf, 0, stsd_data, len);
9426 gst_caps_set_simple (stream->caps,
9427 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9428 gst_buffer_unref (buf);
9434 gst_caps_set_simple (stream->caps,
9435 "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
9442 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
9443 xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
9447 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
9451 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
9452 /* collect the headers and store them in a stream list so that we can
9453 * send them out first */
9454 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
9464 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
9465 ovc1 = qtdemux_tree_get_child_by_type (stsd, FOURCC_ovc1);
9468 ovc1_data = ovc1->data;
9469 ovc1_len = QT_UINT32 (ovc1_data);
9470 if (ovc1_len <= 198) {
9471 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
9474 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
9475 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
9476 gst_caps_set_simple (stream->caps,
9477 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9478 gst_buffer_unref (buf);
9483 gint len = QT_UINT32 (stsd_data) - 0x66;
9484 const guint8 *vc1_data = stsd_data + 0x66;
9490 if (QT_UINT32 (vc1_data) <= len)
9491 size = QT_UINT32 (vc1_data) - 8;
9496 /* No real data, so break out */
9499 switch (QT_FOURCC (vc1_data + 0x4)) {
9500 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
9504 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
9505 buf = gst_buffer_new_and_alloc (size);
9506 gst_buffer_fill (buf, 0, vc1_data + 8, size);
9507 gst_caps_set_simple (stream->caps,
9508 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9509 gst_buffer_unref (buf);
9516 vc1_data += size + 8;
9525 GST_INFO_OBJECT (qtdemux,
9526 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
9527 GST_FOURCC_ARGS (fourcc), stream->caps);
9529 } else if (stream->subtype == FOURCC_soun) {
9530 int version, samplesize;
9531 guint16 compression_id;
9532 gboolean amrwb = FALSE;
9535 /* sample description entry (16) + sound sample description v0 (20) */
9539 version = QT_UINT32 (stsd_data + offset);
9540 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
9541 samplesize = QT_UINT16 (stsd_data + offset + 10);
9542 compression_id = QT_UINT16 (stsd_data + offset + 12);
9543 stream->rate = QT_FP32 (stsd_data + offset + 16);
9545 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
9546 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
9547 QT_UINT32 (stsd_data + offset + 4));
9548 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
9549 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
9550 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
9551 GST_LOG_OBJECT (qtdemux, "packet size: %d",
9552 QT_UINT16 (stsd_data + offset + 14));
9553 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
9555 if (compression_id == 0xfffe)
9556 stream->sampled = TRUE;
9558 /* first assume uncompressed audio */
9559 stream->bytes_per_sample = samplesize / 8;
9560 stream->samples_per_frame = stream->n_channels;
9561 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
9562 stream->samples_per_packet = stream->samples_per_frame;
9563 stream->bytes_per_packet = stream->bytes_per_sample;
9567 /* Yes, these have to be hard-coded */
9570 stream->samples_per_packet = 6;
9571 stream->bytes_per_packet = 1;
9572 stream->bytes_per_frame = 1 * stream->n_channels;
9573 stream->bytes_per_sample = 1;
9574 stream->samples_per_frame = 6 * stream->n_channels;
9579 stream->samples_per_packet = 3;
9580 stream->bytes_per_packet = 1;
9581 stream->bytes_per_frame = 1 * stream->n_channels;
9582 stream->bytes_per_sample = 1;
9583 stream->samples_per_frame = 3 * stream->n_channels;
9588 stream->samples_per_packet = 64;
9589 stream->bytes_per_packet = 34;
9590 stream->bytes_per_frame = 34 * stream->n_channels;
9591 stream->bytes_per_sample = 2;
9592 stream->samples_per_frame = 64 * stream->n_channels;
9598 stream->samples_per_packet = 1;
9599 stream->bytes_per_packet = 1;
9600 stream->bytes_per_frame = 1 * stream->n_channels;
9601 stream->bytes_per_sample = 1;
9602 stream->samples_per_frame = 1 * stream->n_channels;
9607 stream->samples_per_packet = 160;
9608 stream->bytes_per_packet = 33;
9609 stream->bytes_per_frame = 33 * stream->n_channels;
9610 stream->bytes_per_sample = 2;
9611 stream->samples_per_frame = 160 * stream->n_channels;
9618 if (version == 0x00010000) {
9619 /* sample description entry (16) + sound sample description v1 (20+16) */
9630 /* only parse extra decoding config for non-pcm audio */
9631 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
9632 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
9633 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
9634 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
9636 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
9637 stream->samples_per_packet);
9638 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
9639 stream->bytes_per_packet);
9640 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
9641 stream->bytes_per_frame);
9642 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
9643 stream->bytes_per_sample);
9645 if (!stream->sampled && stream->bytes_per_packet) {
9646 stream->samples_per_frame = (stream->bytes_per_frame /
9647 stream->bytes_per_packet) * stream->samples_per_packet;
9648 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
9649 stream->samples_per_frame);
9654 } else if (version == 0x00020000) {
9661 /* sample description entry (16) + sound sample description v2 (56) */
9665 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
9666 stream->rate = qtfp.fp;
9667 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
9669 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
9670 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
9671 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
9672 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
9673 QT_UINT32 (stsd_data + offset + 20));
9674 GST_LOG_OBJECT (qtdemux, "format flags: %X",
9675 QT_UINT32 (stsd_data + offset + 24));
9676 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
9677 QT_UINT32 (stsd_data + offset + 28));
9678 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
9679 QT_UINT32 (stsd_data + offset + 32));
9680 } else if (version != 0x00000) {
9681 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x", version);
9685 gst_caps_unref (stream->caps);
9687 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc,
9688 stsd_data + 32, len - 16, &codec);
9696 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
9698 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
9700 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
9702 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
9705 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
9706 gst_caps_set_simple (stream->caps,
9707 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE", NULL);
9714 const guint8 *owma_data;
9715 const gchar *codec_name = NULL;
9719 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
9720 /* FIXME this should also be gst_riff_strf_auds,
9721 * but the latter one is actually missing bits-per-sample :( */
9726 gint32 nSamplesPerSec;
9727 gint32 nAvgBytesPerSec;
9729 gint16 wBitsPerSample;
9734 GST_DEBUG_OBJECT (qtdemux, "parse owma");
9735 owma = qtdemux_tree_get_child_by_type (stsd, FOURCC_owma);
9738 owma_data = owma->data;
9739 owma_len = QT_UINT32 (owma_data);
9740 if (owma_len <= 54) {
9741 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
9744 wfex = (WAVEFORMATEX *) (owma_data + 36);
9745 buf = gst_buffer_new_and_alloc (owma_len - 54);
9746 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
9747 if (wfex->wFormatTag == 0x0161) {
9748 codec_name = "Windows Media Audio";
9750 } else if (wfex->wFormatTag == 0x0162) {
9751 codec_name = "Windows Media Audio 9 Pro";
9753 } else if (wfex->wFormatTag == 0x0163) {
9754 codec_name = "Windows Media Audio 9 Lossless";
9755 /* is that correct? gstffmpegcodecmap.c is missing it, but
9756 * fluendo codec seems to support it */
9760 gst_caps_set_simple (stream->caps,
9761 "codec_data", GST_TYPE_BUFFER, buf,
9762 "wmaversion", G_TYPE_INT, version,
9763 "block_align", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->nBlockAlign),
9764 "bitrate", G_TYPE_INT, GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec),
9765 "width", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
9766 "depth", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
9768 gst_buffer_unref (buf);
9772 codec = g_strdup (codec_name);
9778 gint len = QT_UINT32 (stsd_data) - offset;
9779 const guint8 *wfex_data = stsd_data + offset;
9780 const gchar *codec_name = NULL;
9782 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
9783 /* FIXME this should also be gst_riff_strf_auds,
9784 * but the latter one is actually missing bits-per-sample :( */
9789 gint32 nSamplesPerSec;
9790 gint32 nAvgBytesPerSec;
9792 gint16 wBitsPerSample;
9797 /* FIXME: unify with similar wavformatex parsing code above */
9798 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
9804 if (QT_UINT32 (wfex_data) <= len)
9805 size = QT_UINT32 (wfex_data) - 8;
9810 /* No real data, so break out */
9813 switch (QT_FOURCC (wfex_data + 4)) {
9814 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
9816 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
9821 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
9822 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
9823 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
9824 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
9825 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
9826 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
9827 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
9829 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
9830 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
9831 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
9832 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
9833 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
9834 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
9836 if (wfex.wFormatTag == 0x0161) {
9837 codec_name = "Windows Media Audio";
9839 } else if (wfex.wFormatTag == 0x0162) {
9840 codec_name = "Windows Media Audio 9 Pro";
9842 } else if (wfex.wFormatTag == 0x0163) {
9843 codec_name = "Windows Media Audio 9 Lossless";
9844 /* is that correct? gstffmpegcodecmap.c is missing it, but
9845 * fluendo codec seems to support it */
9849 gst_caps_set_simple (stream->caps,
9850 "wmaversion", G_TYPE_INT, version,
9851 "block_align", G_TYPE_INT, wfex.nBlockAlign,
9852 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
9853 "width", G_TYPE_INT, wfex.wBitsPerSample,
9854 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
9856 if (size > wfex.cbSize) {
9859 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
9860 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
9861 size - wfex.cbSize);
9862 gst_caps_set_simple (stream->caps,
9863 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9864 gst_buffer_unref (buf);
9866 GST_WARNING_OBJECT (qtdemux, "no codec data");
9871 codec = g_strdup (codec_name);
9879 wfex_data += size + 8;
9886 const guint8 *opus_data;
9887 guint8 *channel_mapping = NULL;
9890 guint8 channel_mapping_family;
9891 guint8 stream_count;
9892 guint8 coupled_count;
9895 opus = qtdemux_tree_get_child_by_type (stsd, FOURCC_opus);
9896 opus_data = opus->data;
9898 channels = GST_READ_UINT8 (opus_data + 45);
9899 rate = GST_READ_UINT32_LE (opus_data + 48);
9900 channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
9901 stream_count = GST_READ_UINT8 (opus_data + 55);
9902 coupled_count = GST_READ_UINT8 (opus_data + 56);
9905 channel_mapping = g_malloc (channels * sizeof (guint8));
9906 for (i = 0; i < channels; i++)
9907 channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
9910 stream->caps = gst_codec_utils_opus_create_caps (rate, channels,
9911 channel_mapping_family, stream_count, coupled_count,
9923 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9924 GST_TAG_AUDIO_CODEC, codec, NULL);
9928 /* some bitrate info may have ended up in caps */
9929 s = gst_caps_get_structure (stream->caps, 0);
9930 gst_structure_get_int (s, "bitrate", &bitrate);
9932 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9933 GST_TAG_BITRATE, bitrate, NULL);
9936 if (stream->protected && fourcc == FOURCC_mp4a)
9937 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_enca);
9939 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
9944 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
9946 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
9948 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
9952 /* If the fourcc's bottom 16 bits gives 'sm', then the top
9953 16 bits is a byte-swapped wave-style codec identifier,
9954 and we can find a WAVE header internally to a 'wave' atom here.
9955 This can more clearly be thought of as 'ms' as the top 16 bits, and a
9956 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
9959 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
9960 if (len < offset + 20) {
9961 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
9963 guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
9964 const guint8 *data = stsd_data + offset + 16;
9966 GNode *waveheadernode;
9968 wavenode = g_node_new ((guint8 *) data);
9969 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
9970 const guint8 *waveheader;
9973 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
9974 if (waveheadernode) {
9975 waveheader = (const guint8 *) waveheadernode->data;
9976 headerlen = QT_UINT32 (waveheader);
9978 if (headerlen > 8) {
9979 gst_riff_strf_auds *header = NULL;
9980 GstBuffer *headerbuf;
9986 headerbuf = gst_buffer_new_and_alloc (headerlen);
9987 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
9989 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
9990 headerbuf, &header, &extra)) {
9991 gst_caps_unref (stream->caps);
9992 /* FIXME: Need to do something with the channel reorder map */
9993 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
9994 header, extra, NULL, NULL, NULL);
9997 gst_buffer_unref (extra);
10002 GST_DEBUG ("Didn't find waveheadernode for this codec");
10004 g_node_destroy (wavenode);
10007 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
10011 /* FIXME: what is in the chunk? */
10014 gint len = QT_UINT32 (stsd_data);
10016 /* seems to be always = 116 = 0x74 */
10022 gint len = QT_UINT32 (stsd_data);
10025 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
10027 gst_buffer_fill (buf, 0, stsd_data + 0x4C, len - 0x4C);
10028 gst_caps_set_simple (stream->caps,
10029 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10030 gst_buffer_unref (buf);
10032 gst_caps_set_simple (stream->caps,
10033 "samplesize", G_TYPE_INT, samplesize, NULL);
10038 GNode *alac, *wave = NULL;
10040 /* apparently, m4a has this atom appended directly in the stsd entry,
10041 * while mov has it in a wave atom */
10042 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
10044 /* alac now refers to stsd entry atom */
10045 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
10047 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
10049 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
10052 const guint8 *alac_data = alac->data;
10053 gint len = QT_UINT32 (alac->data);
10057 GST_DEBUG_OBJECT (qtdemux,
10058 "discarding alac atom with unexpected len %d", len);
10060 /* codec-data contains alac atom size and prefix,
10061 * ffmpeg likes it that way, not quite gst-ish though ...*/
10062 buf = gst_buffer_new_and_alloc (len);
10063 gst_buffer_fill (buf, 0, alac->data, len);
10064 gst_caps_set_simple (stream->caps,
10065 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10066 gst_buffer_unref (buf);
10068 stream->bytes_per_frame = QT_UINT32 (alac_data + 12);
10069 stream->n_channels = QT_UINT8 (alac_data + 21);
10070 stream->rate = QT_UINT32 (alac_data + 32);
10073 gst_caps_set_simple (stream->caps,
10074 "samplesize", G_TYPE_INT, samplesize, NULL);
10082 gint len = QT_UINT32 (stsd_data);
10085 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
10088 gst_buffer_fill (buf, 0, stsd_data + 0x34, len - 0x34);
10090 /* If we have enough data, let's try to get the 'damr' atom. See
10091 * the 3GPP container spec (26.244) for more details. */
10092 if ((len - 0x34) > 8 &&
10093 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
10094 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10095 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
10098 gst_caps_set_simple (stream->caps,
10099 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10100 gst_buffer_unref (buf);
10106 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
10107 gint len = QT_UINT32 (stsd_data);
10110 guint16 sound_version = QT_UINT16 (stsd_data + 32);
10112 if (sound_version == 1) {
10113 guint16 channels = QT_UINT16 (stsd_data + 40);
10114 guint32 time_scale = QT_UINT32 (stsd_data + 46);
10115 guint8 codec_data[2];
10117 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
10119 gint sample_rate_index =
10120 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
10122 /* build AAC codec data */
10123 codec_data[0] = profile << 3;
10124 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
10125 codec_data[1] = (sample_rate_index & 0x01) << 7;
10126 codec_data[1] |= (channels & 0xF) << 3;
10128 buf = gst_buffer_new_and_alloc (2);
10129 gst_buffer_fill (buf, 0, codec_data, 2);
10130 gst_caps_set_simple (stream->caps,
10131 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10132 gst_buffer_unref (buf);
10138 GST_INFO_OBJECT (qtdemux,
10139 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
10143 GST_INFO_OBJECT (qtdemux,
10144 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10145 GST_FOURCC_ARGS (fourcc), stream->caps);
10147 } else if (stream->subtype == FOURCC_strm) {
10148 if (fourcc == FOURCC_rtsp) {
10149 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
10151 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
10152 GST_FOURCC_ARGS (fourcc));
10153 goto unknown_stream;
10155 stream->sampled = TRUE;
10156 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
10157 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
10159 stream->sampled = TRUE;
10160 stream->sparse = TRUE;
10163 qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
10165 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10166 GST_TAG_SUBTITLE_CODEC, codec, NULL);
10171 /* hunt for sort-of codec data */
10175 GNode *mp4s = NULL;
10176 GNode *esds = NULL;
10178 /* look for palette in a stsd->mp4s->esds sub-atom */
10179 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
10181 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
10182 if (esds == NULL) {
10184 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
10188 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
10192 GST_INFO_OBJECT (qtdemux,
10193 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
10196 GST_INFO_OBJECT (qtdemux,
10197 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10198 GST_FOURCC_ARGS (fourcc), stream->caps);
10200 /* everything in 1 sample */
10201 stream->sampled = TRUE;
10204 qtdemux_generic_caps (qtdemux, stream, fourcc, stsd_data, &codec);
10206 if (stream->caps == NULL)
10207 goto unknown_stream;
10210 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10211 GST_TAG_SUBTITLE_CODEC, codec, NULL);
10217 /* promote to sampled format */
10218 if (stream->fourcc == FOURCC_samr) {
10219 /* force mono 8000 Hz for AMR */
10220 stream->sampled = TRUE;
10221 stream->n_channels = 1;
10222 stream->rate = 8000;
10223 } else if (stream->fourcc == FOURCC_sawb) {
10224 /* force mono 16000 Hz for AMR-WB */
10225 stream->sampled = TRUE;
10226 stream->n_channels = 1;
10227 stream->rate = 16000;
10228 } else if (stream->fourcc == FOURCC_mp4a) {
10229 stream->sampled = TRUE;
10232 /* collect sample information */
10233 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
10234 goto samples_failed;
10236 if (qtdemux->fragmented) {
10239 /* need all moov samples as basis; probably not many if any at all */
10240 /* prevent moof parsing taking of at this time */
10241 offset = qtdemux->moof_offset;
10242 qtdemux->moof_offset = 0;
10243 if (stream->n_samples &&
10244 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
10245 qtdemux->moof_offset = offset;
10246 goto samples_failed;
10248 qtdemux->moof_offset = 0;
10249 /* movie duration more reliable in this case (e.g. mehd) */
10250 if (qtdemux->segment.duration &&
10251 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
10253 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
10256 /* configure segments */
10257 if (!qtdemux_parse_segments (qtdemux, stream, trak))
10258 goto segments_failed;
10260 /* add some language tag, if useful */
10261 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
10262 strcmp (stream->lang_id, "und")) {
10263 const gchar *lang_code;
10265 /* convert ISO 639-2 code to ISO 639-1 */
10266 lang_code = gst_tag_get_language_code (stream->lang_id);
10267 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10268 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
10271 /* Check for UDTA tags */
10272 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
10273 qtdemux_parse_udta (qtdemux, stream->pending_tags, udta);
10276 /* now we are ready to add the stream */
10277 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
10278 goto too_many_streams;
10280 if (!qtdemux->got_moov) {
10281 qtdemux->streams[qtdemux->n_streams] = stream;
10282 qtdemux->n_streams++;
10283 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
10291 GST_INFO_OBJECT (qtdemux, "skip disabled track");
10293 gst_qtdemux_stream_free (qtdemux, stream);
10298 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10299 (_("This file is corrupt and cannot be played.")), (NULL));
10301 gst_qtdemux_stream_free (qtdemux, stream);
10306 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
10308 gst_qtdemux_stream_free (qtdemux, stream);
10314 /* we posted an error already */
10315 /* free stbl sub-atoms */
10316 gst_qtdemux_stbl_free (stream);
10318 gst_qtdemux_stream_free (qtdemux, stream);
10323 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
10326 gst_qtdemux_stream_free (qtdemux, stream);
10331 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
10332 GST_FOURCC_ARGS (stream->subtype));
10334 gst_qtdemux_stream_free (qtdemux, stream);
10339 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
10340 (_("This file contains too many streams. Only playing first %d"),
10341 GST_QTDEMUX_MAX_STREAMS), (NULL));
10346 /* If we can estimate the overall bitrate, and don't have information about the
10347 * stream bitrate for exactly one stream, this guesses the stream bitrate as
10348 * the overall bitrate minus the sum of the bitrates of all other streams. This
10349 * should be useful for the common case where we have one audio and one video
10350 * stream and can estimate the bitrate of one, but not the other. */
10352 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
10354 QtDemuxStream *stream = NULL;
10355 gint64 size, sys_bitrate, sum_bitrate = 0;
10356 GstClockTime duration;
10360 if (qtdemux->fragmented)
10363 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
10365 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
10367 GST_DEBUG_OBJECT (qtdemux,
10368 "Size in bytes of the stream not known - bailing");
10372 /* Subtract the header size */
10373 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
10374 size, qtdemux->header_size);
10376 if (size < qtdemux->header_size)
10379 size = size - qtdemux->header_size;
10381 if (!gst_qtdemux_get_duration (qtdemux, &duration) ||
10382 duration == GST_CLOCK_TIME_NONE) {
10383 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
10387 for (i = 0; i < qtdemux->n_streams; i++) {
10388 switch (qtdemux->streams[i]->subtype) {
10391 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
10392 qtdemux->streams[i]->caps);
10393 /* retrieve bitrate, prefer avg then max */
10395 if (qtdemux->streams[i]->pending_tags) {
10396 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
10397 GST_TAG_MAXIMUM_BITRATE, &bitrate);
10398 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
10399 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
10400 GST_TAG_NOMINAL_BITRATE, &bitrate);
10401 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
10402 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
10403 GST_TAG_BITRATE, &bitrate);
10404 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
10407 sum_bitrate += bitrate;
10410 GST_DEBUG_OBJECT (qtdemux,
10411 ">1 stream with unknown bitrate - bailing");
10414 stream = qtdemux->streams[i];
10418 /* For other subtypes, we assume no significant impact on bitrate */
10424 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
10428 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
10430 if (sys_bitrate < sum_bitrate) {
10431 /* This can happen, since sum_bitrate might be derived from maximum
10432 * bitrates and not average bitrates */
10433 GST_DEBUG_OBJECT (qtdemux,
10434 "System bitrate less than sum bitrate - bailing");
10438 bitrate = sys_bitrate - sum_bitrate;
10439 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
10440 ", Stream bitrate = %u", sys_bitrate, bitrate);
10442 if (!stream->pending_tags)
10443 stream->pending_tags = gst_tag_list_new_empty ();
10445 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10446 GST_TAG_BITRATE, bitrate, NULL);
10449 static GstFlowReturn
10450 qtdemux_prepare_streams (GstQTDemux * qtdemux)
10453 GstFlowReturn ret = GST_FLOW_OK;
10455 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
10457 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
10458 QtDemuxStream *stream = qtdemux->streams[i];
10459 guint32 sample_num = 0;
10461 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
10462 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
10464 if (qtdemux->fragmented) {
10465 /* need all moov samples first */
10466 GST_OBJECT_LOCK (qtdemux);
10467 while (stream->n_samples == 0)
10468 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
10470 GST_OBJECT_UNLOCK (qtdemux);
10472 /* discard any stray moof */
10473 qtdemux->moof_offset = 0;
10476 /* prepare braking */
10477 if (ret != GST_FLOW_ERROR)
10480 /* in pull mode, we should have parsed some sample info by now;
10481 * and quite some code will not handle no samples.
10482 * in push mode, we'll just have to deal with it */
10483 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
10484 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
10485 gst_qtdemux_remove_stream (qtdemux, i);
10490 /* parse the initial sample for use in setting the frame rate cap */
10491 while (sample_num == 0 && sample_num < stream->n_samples) {
10492 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
10496 if (stream->n_samples > 0 && stream->stbl_index >= 0) {
10497 stream->first_duration = stream->samples[0].duration;
10498 GST_LOG_OBJECT (qtdemux, "stream %d first duration %u",
10499 stream->track_id, stream->first_duration);
10506 static GstFlowReturn
10507 qtdemux_expose_streams (GstQTDemux * qtdemux)
10510 GstFlowReturn ret = GST_FLOW_OK;
10511 GSList *oldpads = NULL;
10514 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
10516 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
10517 QtDemuxStream *stream = qtdemux->streams[i];
10518 GstPad *oldpad = stream->pad;
10521 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
10522 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
10524 if ((stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl) &&
10525 stream->track_id == qtdemux->chapters_track_id) {
10526 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
10527 so that it doesn't look like a subtitle track */
10528 gst_qtdemux_remove_stream (qtdemux, i);
10533 /* now we have all info and can expose */
10534 list = stream->pending_tags;
10535 stream->pending_tags = NULL;
10537 oldpads = g_slist_prepend (oldpads, oldpad);
10538 gst_qtdemux_add_stream (qtdemux, stream, list);
10541 gst_qtdemux_guess_bitrate (qtdemux);
10543 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
10545 for (iter = oldpads; iter; iter = g_slist_next (iter)) {
10546 GstPad *oldpad = iter->data;
10548 gst_pad_push_event (oldpad, gst_event_new_eos ());
10549 gst_pad_set_active (oldpad, FALSE);
10550 gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
10551 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, oldpad);
10552 gst_object_unref (oldpad);
10555 /* check if we should post a redirect in case there is a single trak
10556 * and it is a redirecting trak */
10557 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
10560 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
10561 "an external content");
10562 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
10563 gst_structure_new ("redirect",
10564 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
10566 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
10567 qtdemux->posted_redirect = TRUE;
10570 for (i = 0; i < qtdemux->n_streams; i++) {
10571 QtDemuxStream *stream = qtdemux->streams[i];
10573 qtdemux_do_allocation (qtdemux, stream);
10576 qtdemux->exposed = TRUE;
10580 /* check if major or compatible brand is 3GP */
10581 static inline gboolean
10582 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
10585 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
10587 } else if (qtdemux->comp_brands != NULL) {
10591 gboolean res = FALSE;
10593 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
10596 while (size >= 4) {
10597 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
10602 gst_buffer_unmap (qtdemux->comp_brands, &map);
10609 /* check if tag is a spec'ed 3GP tag keyword storing a string */
10610 static inline gboolean
10611 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
10613 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
10614 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
10615 || fourcc == FOURCC_albm;
10619 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
10620 const char *tag, const char *dummy, GNode * node)
10622 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
10626 gdouble longitude, latitude, altitude;
10629 len = QT_UINT32 (node->data);
10636 /* TODO: language code skipped */
10638 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
10641 /* do not alarm in trivial case, but bail out otherwise */
10642 if (*(data + offset) != 0) {
10643 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
10647 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
10648 GST_TAG_GEO_LOCATION_NAME, name, NULL);
10649 offset += strlen (name);
10653 if (len < offset + 2 + 4 + 4 + 4)
10656 /* +1 +1 = skip null-terminator and location role byte */
10658 /* table in spec says unsigned, semantics say negative has meaning ... */
10659 longitude = QT_SFP32 (data + offset);
10662 latitude = QT_SFP32 (data + offset);
10665 altitude = QT_SFP32 (data + offset);
10667 /* one invalid means all are invalid */
10668 if (longitude >= -180.0 && longitude <= 180.0 &&
10669 latitude >= -90.0 && latitude <= 90.0) {
10670 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
10671 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
10672 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
10673 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
10676 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
10683 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
10690 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
10691 const char *tag, const char *dummy, GNode * node)
10697 len = QT_UINT32 (node->data);
10701 y = QT_UINT16 ((guint8 *) node->data + 12);
10703 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
10706 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
10708 date = g_date_new_dmy (1, 1, y);
10709 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
10710 g_date_free (date);
10714 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
10715 const char *tag, const char *dummy, GNode * node)
10718 char *tag_str = NULL;
10723 len = QT_UINT32 (node->data);
10728 entity = (guint8 *) node->data + offset;
10729 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
10730 GST_DEBUG_OBJECT (qtdemux,
10731 "classification info: %c%c%c%c invalid classification entity",
10732 entity[0], entity[1], entity[2], entity[3]);
10737 table = QT_UINT16 ((guint8 *) node->data + offset);
10739 /* Language code skipped */
10743 /* Tag format: "XXXX://Y[YYYY]/classification info string"
10744 * XXXX: classification entity, fixed length 4 chars.
10745 * Y[YYYY]: classification table, max 5 chars.
10747 tag_str = g_strdup_printf ("----://%u/%s",
10748 table, (char *) node->data + offset);
10750 /* memcpy To be sure we're preserving byte order */
10751 memcpy (tag_str, entity, 4);
10752 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
10754 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
10763 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
10769 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
10770 const char *tag, const char *dummy, GNode * node)
10772 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
10778 gboolean ret = TRUE;
10779 const gchar *charset = NULL;
10781 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
10783 len = QT_UINT32 (data->data);
10784 type = QT_UINT32 ((guint8 *) data->data + 8);
10785 if (type == 0x00000001 && len > 16) {
10786 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
10789 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
10790 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
10793 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
10797 len = QT_UINT32 (node->data);
10798 type = QT_UINT32 ((guint8 *) node->data + 4);
10799 if ((type >> 24) == 0xa9) {
10803 /* Type starts with the (C) symbol, so the next data is a list
10804 * of (string size(16), language code(16), string) */
10806 str_len = QT_UINT16 ((guint8 *) node->data + 8);
10807 lang_code = QT_UINT16 ((guint8 *) node->data + 10);
10809 /* the string + fourcc + size + 2 16bit fields,
10810 * means that there are more tags in this atom */
10811 if (len > str_len + 8 + 4) {
10812 /* TODO how to represent the same tag in different languages? */
10813 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
10814 "text alternatives, reading only first one");
10818 len = str_len + 8 + 4; /* remove trailing strings that we don't use */
10819 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
10821 if (lang_code < 0x800) { /* MAC encoded string */
10824 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
10825 QT_FOURCC ((guint8 *) node->data + 4))) {
10826 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
10828 /* we go for 3GP style encoding if major brands claims so,
10829 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
10830 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
10831 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
10832 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
10834 /* 16-bit Language code is ignored here as well */
10835 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
10842 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
10843 ret = FALSE; /* may have to fallback */
10846 GError *err = NULL;
10848 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
10849 charset, NULL, NULL, &err);
10851 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
10852 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
10854 g_error_free (err);
10857 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
10858 len - offset, env_vars);
10861 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
10862 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
10866 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
10873 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
10874 const char *tag, const char *dummy, GNode * node)
10876 qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
10880 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
10881 const char *tag, const char *dummy, GNode * node)
10883 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
10885 char *s, *t, *k = NULL;
10890 /* first try normal string tag if major brand not 3GP */
10891 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
10892 if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
10893 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
10894 * let's try it 3gpp way after minor safety check */
10896 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
10902 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
10906 len = QT_UINT32 (data);
10910 count = QT_UINT8 (data + 14);
10912 for (; count; count--) {
10915 if (offset + 1 > len)
10917 slen = QT_UINT8 (data + offset);
10919 if (offset + slen > len)
10921 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
10924 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
10926 t = g_strjoin (",", k, s, NULL);
10934 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
10941 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
10942 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
10951 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
10957 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
10958 const char *tag1, const char *tag2, GNode * node)
10965 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
10967 len = QT_UINT32 (data->data);
10968 type = QT_UINT32 ((guint8 *) data->data + 8);
10969 if (type == 0x00000000 && len >= 22) {
10970 n1 = QT_UINT16 ((guint8 *) data->data + 18);
10971 n2 = QT_UINT16 ((guint8 *) data->data + 20);
10973 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
10974 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
10977 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
10978 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
10985 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
10986 const char *tag1, const char *dummy, GNode * node)
10993 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
10995 len = QT_UINT32 (data->data);
10996 type = QT_UINT32 ((guint8 *) data->data + 8);
10997 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
10998 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
10999 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
11000 n1 = QT_UINT16 ((guint8 *) data->data + 16);
11002 /* do not add bpm=0 */
11003 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
11004 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
11012 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
11013 const char *tag1, const char *dummy, GNode * node)
11020 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11022 len = QT_UINT32 (data->data);
11023 type = QT_UINT32 ((guint8 *) data->data + 8);
11024 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
11025 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
11026 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
11027 num = QT_UINT32 ((guint8 *) data->data + 16);
11029 /* do not add num=0 */
11030 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
11031 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
11038 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
11039 const char *tag1, const char *dummy, GNode * node)
11046 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11048 len = QT_UINT32 (data->data);
11049 type = QT_UINT32 ((guint8 *) data->data + 8);
11050 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
11051 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
11053 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
11054 len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
11055 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
11056 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
11057 gst_sample_unref (sample);
11064 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
11065 const char *tag, const char *dummy, GNode * node)
11072 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11074 len = QT_UINT32 (data->data);
11075 type = QT_UINT32 ((guint8 *) data->data + 8);
11076 if (type == 0x00000001 && len > 16) {
11077 guint y, m = 1, d = 1;
11080 s = g_strndup ((char *) data->data + 16, len - 16);
11081 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
11082 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
11083 if (ret >= 1 && y > 1500 && y < 3000) {
11086 date = g_date_new_dmy (d, m, y);
11087 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
11088 g_date_free (date);
11090 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
11098 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
11099 const char *tag, const char *dummy, GNode * node)
11103 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11105 /* re-route to normal string tag if major brand says so
11106 * or no data atom and compatible brand suggests so */
11107 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
11108 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
11109 qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
11114 guint len, type, n;
11116 len = QT_UINT32 (data->data);
11117 type = QT_UINT32 ((guint8 *) data->data + 8);
11118 if (type == 0x00000000 && len >= 18) {
11119 n = QT_UINT16 ((guint8 *) data->data + 16);
11121 const gchar *genre;
11123 genre = gst_tag_id3_genre_get (n - 1);
11124 if (genre != NULL) {
11125 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
11126 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
11134 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
11135 const gchar * tag, guint8 * data, guint32 datasize)
11140 /* make a copy to have \0 at the end */
11141 datacopy = g_strndup ((gchar *) data, datasize);
11143 /* convert the str to double */
11144 if (sscanf (datacopy, "%lf", &value) == 1) {
11145 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
11146 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
11148 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
11156 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
11157 const char *tag, const char *tag_bis, GNode * node)
11166 const gchar *meanstr;
11167 const gchar *namestr;
11169 /* checking the whole ---- atom size for consistency */
11170 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
11171 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
11175 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
11177 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
11181 meansize = QT_UINT32 (mean->data);
11182 if (meansize <= 12) {
11183 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
11186 meanstr = ((gchar *) mean->data) + 12;
11189 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
11191 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
11195 namesize = QT_UINT32 (name->data);
11196 if (namesize <= 12) {
11197 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
11200 namestr = ((gchar *) name->data) + 12;
11208 * uint24 - data type
11212 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11214 GST_WARNING_OBJECT (demux, "No data atom in this tag");
11217 datasize = QT_UINT32 (data->data);
11218 if (datasize <= 16) {
11219 GST_WARNING_OBJECT (demux, "Data atom too small");
11222 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
11224 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
11225 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
11226 static const struct
11228 const gchar name[28];
11229 const gchar tag[28];
11232 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
11233 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
11234 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
11235 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
11236 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
11237 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
11238 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
11239 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
11243 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
11244 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
11245 switch (gst_tag_get_type (tags[i].tag)) {
11246 case G_TYPE_DOUBLE:
11247 qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
11248 ((guint8 *) data->data) + 16, datasize - 16);
11250 case G_TYPE_STRING:
11251 qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
11260 if (i == G_N_ELEMENTS (tags))
11270 #ifndef GST_DISABLE_GST_DEBUG
11272 gchar *namestr_dbg;
11273 gchar *meanstr_dbg;
11275 meanstr_dbg = g_strndup (meanstr, meansize);
11276 namestr_dbg = g_strndup (namestr, namesize);
11278 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
11279 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
11281 g_free (namestr_dbg);
11282 g_free (meanstr_dbg);
11289 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
11290 const char *tag_bis, GNode * node)
11295 GstTagList *id32_taglist = NULL;
11297 GST_LOG_OBJECT (demux, "parsing ID32");
11300 len = GST_READ_UINT32_BE (data);
11302 /* need at least full box and language tag */
11306 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
11307 gst_buffer_fill (buf, 0, data + 14, len - 14);
11309 id32_taglist = gst_tag_list_from_id3v2_tag (buf);
11310 if (id32_taglist) {
11311 GST_LOG_OBJECT (demux, "parsing ok");
11312 gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
11313 gst_tag_list_unref (id32_taglist);
11315 GST_LOG_OBJECT (demux, "parsing failed");
11318 gst_buffer_unref (buf);
11321 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
11322 const char *tag, const char *tag_bis, GNode * node);
11325 FOURCC_pcst -> if media is a podcast -> bool
11326 FOURCC_cpil -> if media is part of a compilation -> bool
11327 FOURCC_pgap -> if media is part of a gapless context -> bool
11328 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
11331 static const struct
11334 const gchar *gst_tag;
11335 const gchar *gst_tag_bis;
11336 const GstQTDemuxAddTagFunc func;
11339 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
11340 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
11341 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
11342 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
11343 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
11344 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
11345 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
11346 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
11347 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
11348 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
11349 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
11350 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
11351 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
11352 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
11353 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
11354 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
11355 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
11356 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
11357 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
11358 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
11359 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
11360 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
11361 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
11362 qtdemux_tag_add_num}, {
11363 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
11364 qtdemux_tag_add_num}, {
11365 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
11366 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
11367 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
11368 FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
11369 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
11370 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
11371 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
11372 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
11373 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
11374 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
11375 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
11376 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
11377 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
11378 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
11379 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
11380 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
11381 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
11382 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
11383 qtdemux_tag_add_classification}, {
11384 FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
11385 FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
11386 FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
11388 /* This is a special case, some tags are stored in this
11389 * 'reverse dns naming', according to:
11390 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
11393 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
11394 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
11395 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
11398 struct _GstQtDemuxTagList
11401 GstTagList *taglist;
11403 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
11406 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
11412 const gchar *style;
11417 GstQTDemux *demux = qtdemuxtaglist->demux;
11418 GstTagList *taglist = qtdemuxtaglist->taglist;
11421 len = QT_UINT32 (data);
11422 buf = gst_buffer_new_and_alloc (len);
11423 gst_buffer_fill (buf, 0, data, len);
11425 /* heuristic to determine style of tag */
11426 if (QT_FOURCC (data + 4) == FOURCC_____ ||
11427 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
11429 else if (demux->major_brand == FOURCC_qt__)
11430 style = "quicktime";
11431 /* fall back to assuming iso/3gp tag style */
11435 /* santize the name for the caps. */
11436 for (i = 0; i < 4; i++) {
11437 guint8 d = data[4 + i];
11438 if (g_ascii_isalnum (d))
11439 ndata[i] = g_ascii_tolower (d);
11444 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
11445 ndata[0], ndata[1], ndata[2], ndata[3]);
11446 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
11448 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
11449 sample = gst_sample_new (buf, NULL, NULL, s);
11450 gst_buffer_unref (buf);
11451 g_free (media_type);
11453 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
11456 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
11457 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
11459 gst_sample_unref (sample);
11463 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
11470 GstQtDemuxTagList demuxtaglist;
11472 demuxtaglist.demux = qtdemux;
11473 demuxtaglist.taglist = taglist;
11475 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
11476 if (meta != NULL) {
11477 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
11478 if (ilst == NULL) {
11479 GST_LOG_OBJECT (qtdemux, "no ilst");
11484 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
11488 while (i < G_N_ELEMENTS (add_funcs)) {
11489 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
11493 len = QT_UINT32 (node->data);
11495 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
11496 GST_FOURCC_ARGS (add_funcs[i].fourcc));
11498 add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
11499 add_funcs[i].gst_tag_bis, node);
11501 g_node_destroy (node);
11507 /* parsed nodes have been removed, pass along remainder as blob */
11508 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
11509 (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
11511 /* parse up XMP_ node if existing */
11512 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
11513 if (xmp_ != NULL) {
11515 GstTagList *xmptaglist;
11517 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
11518 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
11519 xmptaglist = gst_tag_list_from_xmp_buffer (buf);
11520 gst_buffer_unref (buf);
11522 qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
11524 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
11530 GstStructure *structure; /* helper for sort function */
11532 guint min_req_bitrate;
11533 guint min_req_qt_version;
11537 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
11539 GstQtReference *ref_a = (GstQtReference *) a;
11540 GstQtReference *ref_b = (GstQtReference *) b;
11542 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
11543 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
11545 /* known bitrates go before unknown; higher bitrates go first */
11546 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
11549 /* sort the redirects and post a message for the application.
11552 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
11554 GstQtReference *best;
11557 GValue list_val = { 0, };
11560 g_assert (references != NULL);
11562 references = g_list_sort (references, qtdemux_redirects_sort_func);
11564 best = (GstQtReference *) references->data;
11566 g_value_init (&list_val, GST_TYPE_LIST);
11568 for (l = references; l != NULL; l = l->next) {
11569 GstQtReference *ref = (GstQtReference *) l->data;
11570 GValue struct_val = { 0, };
11572 ref->structure = gst_structure_new ("redirect",
11573 "new-location", G_TYPE_STRING, ref->location, NULL);
11575 if (ref->min_req_bitrate > 0) {
11576 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
11577 ref->min_req_bitrate, NULL);
11580 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
11581 g_value_set_boxed (&struct_val, ref->structure);
11582 gst_value_list_append_value (&list_val, &struct_val);
11583 g_value_unset (&struct_val);
11584 /* don't free anything here yet, since we need best->structure below */
11587 g_assert (best != NULL);
11588 s = gst_structure_copy (best->structure);
11590 if (g_list_length (references) > 1) {
11591 gst_structure_set_value (s, "locations", &list_val);
11594 g_value_unset (&list_val);
11596 for (l = references; l != NULL; l = l->next) {
11597 GstQtReference *ref = (GstQtReference *) l->data;
11599 gst_structure_free (ref->structure);
11600 g_free (ref->location);
11603 g_list_free (references);
11605 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
11606 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
11607 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
11608 qtdemux->posted_redirect = TRUE;
11611 /* look for redirect nodes, collect all redirect information and
11615 qtdemux_parse_redirects (GstQTDemux * qtdemux)
11617 GNode *rmra, *rmda, *rdrf;
11619 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
11621 GList *redirects = NULL;
11623 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
11625 GstQtReference ref = { NULL, NULL, 0, 0 };
11626 GNode *rmdr, *rmvc;
11628 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
11629 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
11630 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
11631 ref.min_req_bitrate);
11634 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
11635 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
11636 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
11638 #ifndef GST_DISABLE_GST_DEBUG
11639 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
11641 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
11643 GST_LOG_OBJECT (qtdemux,
11644 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
11645 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
11646 bitmask, check_type);
11647 if (package == FOURCC_qtim && check_type == 0) {
11648 ref.min_req_qt_version = version;
11652 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
11658 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
11659 if (ref_len > 20) {
11660 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
11661 ref_data = (guint8 *) rdrf->data + 20;
11662 if (ref_type == FOURCC_alis) {
11663 guint record_len, record_version, fn_len;
11665 if (ref_len > 70) {
11666 /* MacOSX alias record, google for alias-layout.txt */
11667 record_len = QT_UINT16 (ref_data + 4);
11668 record_version = QT_UINT16 (ref_data + 4 + 2);
11669 fn_len = QT_UINT8 (ref_data + 50);
11670 if (record_len > 50 && record_version == 2 && fn_len > 0) {
11671 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
11674 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
11677 } else if (ref_type == FOURCC_url_) {
11678 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
11680 GST_DEBUG_OBJECT (qtdemux,
11681 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
11682 GST_FOURCC_ARGS (ref_type));
11684 if (ref.location != NULL) {
11685 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
11687 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
11689 GST_WARNING_OBJECT (qtdemux,
11690 "Failed to extract redirect location from rdrf atom");
11693 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
11697 /* look for others */
11698 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
11701 if (redirects != NULL) {
11702 qtdemux_process_redirects (qtdemux, redirects);
11708 static GstTagList *
11709 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
11713 if (tags == NULL) {
11714 tags = gst_tag_list_new_empty ();
11715 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
11718 if (qtdemux->major_brand == FOURCC_mjp2)
11719 fmt = "Motion JPEG 2000";
11720 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
11722 else if (qtdemux->major_brand == FOURCC_qt__)
11724 else if (qtdemux->fragmented)
11727 fmt = "ISO MP4/M4A";
11729 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
11730 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
11732 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
11738 /* we have read th complete moov node now.
11739 * This function parses all of the relevant info, creates the traks and
11740 * prepares all data structures for playback
11743 qtdemux_parse_tree (GstQTDemux * qtdemux)
11749 GstClockTime duration;
11751 guint64 creation_time;
11752 GstDateTime *datetime = NULL;
11755 /* make sure we have a usable taglist */
11756 if (!qtdemux->tag_list) {
11757 qtdemux->tag_list = gst_tag_list_new_empty ();
11758 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
11760 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
11763 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
11764 if (mvhd == NULL) {
11765 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
11766 return qtdemux_parse_redirects (qtdemux);
11769 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
11770 if (version == 1) {
11771 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
11772 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
11773 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
11774 } else if (version == 0) {
11775 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
11776 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
11777 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
11779 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
11783 /* Moving qt creation time (secs since 1904) to unix time */
11784 if (creation_time != 0) {
11785 /* Try to use epoch first as it should be faster and more commonly found */
11786 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
11789 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
11790 /* some data cleansing sanity */
11791 g_get_current_time (&now);
11792 if (now.tv_sec + 24 * 3600 < creation_time) {
11793 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
11795 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
11798 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
11799 GDateTime *dt, *dt_local;
11801 dt = g_date_time_add_seconds (base_dt, creation_time);
11802 dt_local = g_date_time_to_local (dt);
11803 datetime = gst_date_time_new_from_g_date_time (dt_local);
11805 g_date_time_unref (base_dt);
11806 g_date_time_unref (dt);
11810 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
11811 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
11813 gst_date_time_unref (datetime);
11816 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
11817 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
11819 /* check for fragmented file and get some (default) data */
11820 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
11823 GstByteReader mehd_data;
11825 /* let track parsing or anyone know weird stuff might happen ... */
11826 qtdemux->fragmented = TRUE;
11828 /* compensate for total duration */
11829 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
11831 qtdemux_parse_mehd (qtdemux, &mehd_data);
11834 /* set duration in the segment info */
11835 gst_qtdemux_get_duration (qtdemux, &duration);
11837 qtdemux->segment.duration = duration;
11838 /* also do not exceed duration; stop is set that way post seek anyway,
11839 * and segment activation falls back to duration,
11840 * whereas loop only checks stop, so let's align this here as well */
11841 qtdemux->segment.stop = duration;
11844 /* parse all traks */
11845 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
11847 qtdemux_parse_trak (qtdemux, trak);
11848 /* iterate all siblings */
11849 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
11852 if (!qtdemux->tag_list) {
11853 GST_DEBUG_OBJECT (qtdemux, "new tag list");
11854 qtdemux->tag_list = gst_tag_list_new_empty ();
11855 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
11857 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
11861 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
11863 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
11865 GST_LOG_OBJECT (qtdemux, "No udta node found.");
11868 /* maybe also some tags in meta box */
11869 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
11871 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
11872 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
11874 GST_LOG_OBJECT (qtdemux, "No meta node found.");
11877 /* parse any protection system info */
11878 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
11880 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
11881 qtdemux_parse_pssh (qtdemux, pssh);
11882 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
11885 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
11890 /* taken from ffmpeg */
11892 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
11904 len = (len << 7) | (c & 0x7f);
11912 /* this can change the codec originally present in @list */
11914 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
11915 GNode * esds, GstTagList * list)
11917 int len = QT_UINT32 (esds->data);
11918 guint8 *ptr = esds->data;
11919 guint8 *end = ptr + len;
11921 guint8 *data_ptr = NULL;
11923 guint8 object_type_id = 0;
11924 const char *codec_name = NULL;
11925 GstCaps *caps = NULL;
11927 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
11929 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
11931 while (ptr + 1 < end) {
11932 tag = QT_UINT8 (ptr);
11933 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
11935 len = read_descr_size (ptr, end, &ptr);
11936 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
11938 /* Check the stated amount of data is available for reading */
11939 if (len < 0 || ptr + len > end)
11943 case ES_DESCRIPTOR_TAG:
11944 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
11945 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
11948 case DECODER_CONFIG_DESC_TAG:{
11949 guint max_bitrate, avg_bitrate;
11951 object_type_id = QT_UINT8 (ptr);
11952 max_bitrate = QT_UINT32 (ptr + 5);
11953 avg_bitrate = QT_UINT32 (ptr + 9);
11954 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
11955 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
11956 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
11957 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
11958 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
11959 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
11960 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
11961 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
11963 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
11964 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
11965 avg_bitrate, NULL);
11970 case DECODER_SPECIFIC_INFO_TAG:
11971 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
11972 if (object_type_id == 0xe0 && len == 0x40) {
11978 GST_DEBUG_OBJECT (qtdemux,
11979 "Have VOBSUB palette. Creating palette event");
11980 /* move to decConfigDescr data and read palette */
11982 for (i = 0; i < 16; i++) {
11983 clut[i] = QT_UINT32 (data);
11987 s = gst_structure_new ("application/x-gst-dvd", "event",
11988 G_TYPE_STRING, "dvd-spu-clut-change",
11989 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
11990 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
11991 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
11992 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
11993 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
11994 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
11995 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
11996 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
11999 /* store event and trigger custom processing */
12000 stream->pending_event =
12001 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
12003 /* Generic codec_data handler puts it on the caps */
12010 case SL_CONFIG_DESC_TAG:
12011 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
12015 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
12017 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
12023 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
12024 * in use, and should also be used to override some other parameters for some
12026 switch (object_type_id) {
12027 case 0x20: /* MPEG-4 */
12028 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
12029 * profile_and_level_indication */
12030 if (data_ptr != NULL && data_len >= 5 &&
12031 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
12032 gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
12033 data_ptr + 4, data_len - 4);
12035 break; /* Nothing special needed here */
12036 case 0x21: /* H.264 */
12037 codec_name = "H.264 / AVC";
12038 caps = gst_caps_new_simple ("video/x-h264",
12039 "stream-format", G_TYPE_STRING, "avc",
12040 "alignment", G_TYPE_STRING, "au", NULL);
12042 case 0x40: /* AAC (any) */
12043 case 0x66: /* AAC Main */
12044 case 0x67: /* AAC LC */
12045 case 0x68: /* AAC SSR */
12046 /* Override channels and rate based on the codec_data, as it's often
12048 /* Only do so for basic setup without HE-AAC extension */
12049 if (data_ptr && data_len == 2) {
12050 guint channels, rateindex, rate;
12052 /* FIXME: add gst_codec_utils_aac_get_{channels|sample_rate}()? */
12053 channels = (data_ptr[1] & 0x7f) >> 3;
12054 if (channels > 0 && channels < 7) {
12055 stream->n_channels = channels;
12056 } else if (channels == 7) {
12057 stream->n_channels = 8;
12060 rateindex = ((data_ptr[0] & 0x7) << 1) | ((data_ptr[1] & 0x80) >> 7);
12061 rate = gst_codec_utils_aac_get_sample_rate_from_index (rateindex);
12063 stream->rate = rate;
12066 /* Set level and profile if possible */
12067 if (data_ptr != NULL && data_len >= 2) {
12068 gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
12069 data_ptr, data_len);
12072 case 0x60: /* MPEG-2, various profiles */
12078 codec_name = "MPEG-2 video";
12079 caps = gst_caps_new_simple ("video/mpeg",
12080 "mpegversion", G_TYPE_INT, 2,
12081 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12083 case 0x69: /* MPEG-2 BC audio */
12084 case 0x6B: /* MPEG-1 audio */
12085 caps = gst_caps_new_simple ("audio/mpeg",
12086 "mpegversion", G_TYPE_INT, 1, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
12087 codec_name = "MPEG-1 audio";
12089 case 0x6A: /* MPEG-1 */
12090 codec_name = "MPEG-1 video";
12091 caps = gst_caps_new_simple ("video/mpeg",
12092 "mpegversion", G_TYPE_INT, 1,
12093 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12095 case 0x6C: /* MJPEG */
12097 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
12099 codec_name = "Motion-JPEG";
12101 case 0x6D: /* PNG */
12103 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
12105 codec_name = "PNG still images";
12107 case 0x6E: /* JPEG2000 */
12108 codec_name = "JPEG-2000";
12109 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
12111 case 0xA4: /* Dirac */
12112 codec_name = "Dirac";
12113 caps = gst_caps_new_empty_simple ("video/x-dirac");
12115 case 0xA5: /* AC3 */
12116 codec_name = "AC-3 audio";
12117 caps = gst_caps_new_simple ("audio/x-ac3",
12118 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12120 case 0xA9: /* AC3 */
12121 codec_name = "DTS audio";
12122 caps = gst_caps_new_simple ("audio/x-dts",
12123 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12125 case 0xE1: /* QCELP */
12126 /* QCELP, the codec_data is a riff tag (little endian) with
12127 * 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). */
12128 caps = gst_caps_new_empty_simple ("audio/qcelp");
12129 codec_name = "QCELP";
12135 /* If we have a replacement caps, then change our caps for this stream */
12137 gst_caps_unref (stream->caps);
12138 stream->caps = caps;
12141 if (codec_name && list)
12142 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
12143 GST_TAG_AUDIO_CODEC, codec_name, NULL);
12145 /* Add the codec_data attribute to caps, if we have it */
12149 buffer = gst_buffer_new_and_alloc (data_len);
12150 gst_buffer_fill (buffer, 0, data_ptr, data_len);
12152 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
12153 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
12155 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
12157 gst_buffer_unref (buffer);
12162 #define _codec(name) \
12164 if (codec_name) { \
12165 *codec_name = g_strdup (name); \
12170 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
12171 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
12173 GstCaps *caps = NULL;
12174 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
12177 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
12178 _codec ("PNG still images");
12179 caps = gst_caps_new_empty_simple ("image/png");
12182 _codec ("JPEG still images");
12184 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
12187 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
12188 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
12189 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
12190 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
12191 _codec ("Motion-JPEG");
12193 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
12196 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
12197 _codec ("Motion-JPEG format B");
12198 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
12201 _codec ("JPEG-2000");
12202 /* override to what it should be according to spec, avoid palette_data */
12203 stream->bits_per_sample = 24;
12204 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
12207 _codec ("Sorensen video v.3");
12208 caps = gst_caps_new_simple ("video/x-svq",
12209 "svqversion", G_TYPE_INT, 3, NULL);
12211 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
12212 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
12213 _codec ("Sorensen video v.1");
12214 caps = gst_caps_new_simple ("video/x-svq",
12215 "svqversion", G_TYPE_INT, 1, NULL);
12217 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
12218 caps = gst_caps_new_empty_simple ("video/x-raw");
12219 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
12220 _codec ("Windows Raw RGB");
12226 bps = QT_UINT16 (stsd_data + 98);
12229 format = GST_VIDEO_FORMAT_RGB15;
12232 format = GST_VIDEO_FORMAT_RGB16;
12235 format = GST_VIDEO_FORMAT_RGB;
12238 format = GST_VIDEO_FORMAT_ARGB;
12246 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
12247 format = GST_VIDEO_FORMAT_I420;
12249 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
12250 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
12251 format = GST_VIDEO_FORMAT_I420;
12254 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
12255 format = GST_VIDEO_FORMAT_UYVY;
12257 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
12258 format = GST_VIDEO_FORMAT_v308;
12260 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
12261 format = GST_VIDEO_FORMAT_v216;
12264 format = GST_VIDEO_FORMAT_v210;
12266 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
12267 format = GST_VIDEO_FORMAT_r210;
12269 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
12270 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
12271 format = GST_VIDEO_FORMAT_v410;
12274 /* Packed YUV 4:4:4:4 8 bit in 32 bits
12275 * but different order than AYUV
12276 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
12277 format = GST_VIDEO_FORMAT_v408;
12280 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
12281 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
12282 _codec ("MPEG-1 video");
12283 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
12284 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12286 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
12287 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
12288 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
12289 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
12290 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
12291 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
12292 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
12293 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
12294 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
12295 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
12296 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
12297 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
12298 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
12299 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
12300 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
12301 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
12302 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
12303 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
12304 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
12305 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
12306 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
12307 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
12308 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
12309 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
12310 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
12311 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
12312 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
12313 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
12314 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
12315 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
12316 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
12317 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
12318 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
12319 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
12320 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
12321 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
12322 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
12323 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
12324 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
12325 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
12326 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
12327 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
12328 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
12329 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
12330 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
12331 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
12332 _codec ("MPEG-2 video");
12333 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
12334 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12336 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
12337 _codec ("GIF still images");
12338 caps = gst_caps_new_empty_simple ("image/gif");
12341 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
12343 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
12345 /* ffmpeg uses the height/width props, don't know why */
12346 caps = gst_caps_new_simple ("video/x-h263",
12347 "variant", G_TYPE_STRING, "itu", NULL);
12351 _codec ("MPEG-4 video");
12352 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
12353 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12355 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
12356 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
12357 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
12358 caps = gst_caps_new_simple ("video/x-msmpeg",
12359 "msmpegversion", G_TYPE_INT, 43, NULL);
12361 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
12363 caps = gst_caps_new_simple ("video/x-divx",
12364 "divxversion", G_TYPE_INT, 3, NULL);
12366 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
12367 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
12369 caps = gst_caps_new_simple ("video/x-divx",
12370 "divxversion", G_TYPE_INT, 4, NULL);
12372 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
12374 caps = gst_caps_new_simple ("video/x-divx",
12375 "divxversion", G_TYPE_INT, 5, NULL);
12378 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
12380 caps = gst_caps_new_simple ("video/x-ffv",
12381 "ffvversion", G_TYPE_INT, 1, NULL);
12384 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
12385 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
12386 case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
12387 case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
12389 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
12390 caps = gst_caps_new_simple ("video/mpeg",
12391 "mpegversion", G_TYPE_INT, 4, NULL);
12395 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
12396 _codec ("Cinepak");
12397 caps = gst_caps_new_empty_simple ("video/x-cinepak");
12399 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
12400 _codec ("Apple QuickDraw");
12401 caps = gst_caps_new_empty_simple ("video/x-qdrw");
12403 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
12404 _codec ("Apple video");
12405 caps = gst_caps_new_empty_simple ("video/x-apple-video");
12409 _codec ("H.264 / AVC");
12410 caps = gst_caps_new_simple ("video/x-h264",
12411 "stream-format", G_TYPE_STRING, "avc",
12412 "alignment", G_TYPE_STRING, "au", NULL);
12415 _codec ("H.264 / AVC");
12416 caps = gst_caps_new_simple ("video/x-h264",
12417 "stream-format", G_TYPE_STRING, "avc3",
12418 "alignment", G_TYPE_STRING, "au", NULL);
12422 _codec ("H.265 / HEVC");
12423 caps = gst_caps_new_simple ("video/x-h265",
12424 "stream-format", G_TYPE_STRING, "hvc1",
12425 "alignment", G_TYPE_STRING, "au", NULL);
12428 _codec ("H.265 / HEVC");
12429 caps = gst_caps_new_simple ("video/x-h265",
12430 "stream-format", G_TYPE_STRING, "hev1",
12431 "alignment", G_TYPE_STRING, "au", NULL);
12434 _codec ("Run-length encoding");
12435 caps = gst_caps_new_simple ("video/x-rle",
12436 "layout", G_TYPE_STRING, "quicktime", NULL);
12439 _codec ("Run-length encoding");
12440 caps = gst_caps_new_simple ("video/x-rle",
12441 "layout", G_TYPE_STRING, "microsoft", NULL);
12443 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
12444 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
12445 _codec ("Indeo Video 3");
12446 caps = gst_caps_new_simple ("video/x-indeo",
12447 "indeoversion", G_TYPE_INT, 3, NULL);
12449 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
12450 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
12451 _codec ("Intel Video 4");
12452 caps = gst_caps_new_simple ("video/x-indeo",
12453 "indeoversion", G_TYPE_INT, 4, NULL);
12457 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
12458 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
12459 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
12460 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
12461 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
12462 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
12463 _codec ("DV Video");
12464 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
12465 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12467 case FOURCC_dv5n: /* DVCPRO50 NTSC */
12468 case FOURCC_dv5p: /* DVCPRO50 PAL */
12469 _codec ("DVCPro50 Video");
12470 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
12471 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12473 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
12474 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
12475 _codec ("DVCProHD Video");
12476 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
12477 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12479 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
12480 _codec ("Apple Graphics (SMC)");
12481 caps = gst_caps_new_empty_simple ("video/x-smc");
12483 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
12485 caps = gst_caps_new_empty_simple ("video/x-vp3");
12487 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
12488 _codec ("VP6 Flash");
12489 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
12493 caps = gst_caps_new_empty_simple ("video/x-theora");
12494 /* theora uses one byte of padding in the data stream because it does not
12495 * allow 0 sized packets while theora does */
12496 stream->padding = 1;
12500 caps = gst_caps_new_empty_simple ("video/x-dirac");
12502 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
12503 _codec ("TIFF still images");
12504 caps = gst_caps_new_empty_simple ("image/tiff");
12506 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
12507 _codec ("Apple Intermediate Codec");
12508 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
12510 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
12511 _codec ("AVID DNxHD");
12512 caps = gst_caps_from_string ("video/x-dnxhd");
12515 _codec ("On2 VP8");
12516 caps = gst_caps_from_string ("video/x-vp8");
12519 _codec ("Apple ProRes LT");
12521 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
12525 _codec ("Apple ProRes HQ");
12527 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
12531 _codec ("Apple ProRes");
12533 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
12537 _codec ("Apple ProRes Proxy");
12539 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
12543 _codec ("Apple ProRes 4444");
12545 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
12551 caps = gst_caps_new_simple ("video/x-wmv",
12552 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
12554 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
12557 char *s, fourstr[5];
12559 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12560 s = g_strdup_printf ("video/x-gst-fourcc-%s", g_strstrip (fourstr));
12561 caps = gst_caps_new_empty_simple (s);
12567 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
12570 gst_video_info_init (&info);
12571 gst_video_info_set_format (&info, format, stream->width, stream->height);
12573 caps = gst_video_info_to_caps (&info);
12574 *codec_name = gst_pb_utils_get_codec_description (caps);
12576 /* enable clipping for raw video streams */
12577 stream->need_clip = TRUE;
12584 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
12585 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
12588 const GstStructure *s;
12591 GstAudioFormat format = 0;
12594 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
12596 depth = stream->bytes_per_packet * 8;
12599 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
12601 /* 8-bit audio is unsigned */
12603 format = GST_AUDIO_FORMAT_U8;
12604 /* otherwise it's signed and big-endian just like 'twos' */
12606 endian = G_BIG_ENDIAN;
12613 endian = G_LITTLE_ENDIAN;
12616 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
12618 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
12622 caps = gst_caps_new_simple ("audio/x-raw",
12623 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
12624 "layout", G_TYPE_STRING, "interleaved", NULL);
12627 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
12628 _codec ("Raw 64-bit floating-point audio");
12629 caps = gst_caps_new_simple ("audio/x-raw",
12630 "format", G_TYPE_STRING, "F64BE",
12631 "layout", G_TYPE_STRING, "interleaved", NULL);
12633 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
12634 _codec ("Raw 32-bit floating-point audio");
12635 caps = gst_caps_new_simple ("audio/x-raw",
12636 "format", G_TYPE_STRING, "F32BE",
12637 "layout", G_TYPE_STRING, "interleaved", NULL);
12640 _codec ("Raw 24-bit PCM audio");
12641 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
12643 caps = gst_caps_new_simple ("audio/x-raw",
12644 "format", G_TYPE_STRING, "S24BE",
12645 "layout", G_TYPE_STRING, "interleaved", NULL);
12647 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
12648 _codec ("Raw 32-bit PCM audio");
12649 caps = gst_caps_new_simple ("audio/x-raw",
12650 "format", G_TYPE_STRING, "S32BE",
12651 "layout", G_TYPE_STRING, "interleaved", NULL);
12654 _codec ("Mu-law audio");
12655 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
12658 _codec ("A-law audio");
12659 caps = gst_caps_new_empty_simple ("audio/x-alaw");
12663 _codec ("Microsoft ADPCM");
12664 /* Microsoft ADPCM-ACM code 2 */
12665 caps = gst_caps_new_simple ("audio/x-adpcm",
12666 "layout", G_TYPE_STRING, "microsoft", NULL);
12670 _codec ("DVI/IMA ADPCM");
12671 caps = gst_caps_new_simple ("audio/x-adpcm",
12672 "layout", G_TYPE_STRING, "dvi", NULL);
12676 _codec ("DVI/Intel IMA ADPCM");
12677 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
12678 caps = gst_caps_new_simple ("audio/x-adpcm",
12679 "layout", G_TYPE_STRING, "quicktime", NULL);
12683 /* MPEG layer 3, CBR only (pre QT4.1) */
12685 _codec ("MPEG-1 layer 3");
12686 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
12687 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
12688 "mpegversion", G_TYPE_INT, 1, NULL);
12691 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
12692 _codec ("EAC-3 audio");
12693 caps = gst_caps_new_simple ("audio/x-eac3",
12694 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12695 stream->sampled = TRUE;
12697 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
12699 _codec ("AC-3 audio");
12700 caps = gst_caps_new_simple ("audio/x-ac3",
12701 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12702 stream->sampled = TRUE;
12704 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
12705 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
12706 _codec ("DTS audio");
12707 caps = gst_caps_new_simple ("audio/x-dts",
12708 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12709 stream->sampled = TRUE;
12711 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
12712 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
12713 _codec ("DTS-HD audio");
12714 caps = gst_caps_new_simple ("audio/x-dts",
12715 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12716 stream->sampled = TRUE;
12720 caps = gst_caps_new_simple ("audio/x-mace",
12721 "maceversion", G_TYPE_INT, 3, NULL);
12725 caps = gst_caps_new_simple ("audio/x-mace",
12726 "maceversion", G_TYPE_INT, 6, NULL);
12728 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
12730 caps = gst_caps_new_empty_simple ("application/ogg");
12732 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
12733 _codec ("DV audio");
12734 caps = gst_caps_new_empty_simple ("audio/x-dv");
12737 _codec ("MPEG-4 AAC audio");
12738 caps = gst_caps_new_simple ("audio/mpeg",
12739 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
12740 "stream-format", G_TYPE_STRING, "raw", NULL);
12742 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
12743 _codec ("QDesign Music");
12744 caps = gst_caps_new_empty_simple ("audio/x-qdm");
12747 _codec ("QDesign Music v.2");
12748 /* FIXME: QDesign music version 2 (no constant) */
12749 if (FALSE && data) {
12750 caps = gst_caps_new_simple ("audio/x-qdm2",
12751 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
12752 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
12753 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
12755 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
12759 _codec ("GSM audio");
12760 caps = gst_caps_new_empty_simple ("audio/x-gsm");
12763 _codec ("AMR audio");
12764 caps = gst_caps_new_empty_simple ("audio/AMR");
12767 _codec ("AMR-WB audio");
12768 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
12771 _codec ("Quicktime IMA ADPCM");
12772 caps = gst_caps_new_simple ("audio/x-adpcm",
12773 "layout", G_TYPE_STRING, "quicktime", NULL);
12776 _codec ("Apple lossless audio");
12777 caps = gst_caps_new_empty_simple ("audio/x-alac");
12779 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
12780 _codec ("QualComm PureVoice");
12781 caps = gst_caps_from_string ("audio/qcelp");
12786 caps = gst_caps_new_empty_simple ("audio/x-wma");
12790 caps = gst_caps_new_empty_simple ("audio/x-opus");
12792 case GST_MAKE_FOURCC ('l', 'p', 'c', 'm'):
12797 GstAudioFormat format;
12800 FLAG_IS_FLOAT = 0x1,
12801 FLAG_IS_BIG_ENDIAN = 0x2,
12802 FLAG_IS_SIGNED = 0x4,
12803 FLAG_IS_PACKED = 0x8,
12804 FLAG_IS_ALIGNED_HIGH = 0x10,
12805 FLAG_IS_NON_INTERLEAVED = 0x20
12807 _codec ("Raw LPCM audio");
12809 if (data && len >= 56) {
12810 depth = QT_UINT32 (data + 40);
12811 flags = QT_UINT32 (data + 44);
12812 width = QT_UINT32 (data + 48) * 8 / stream->n_channels;
12814 if ((flags & FLAG_IS_FLOAT) == 0) {
12819 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
12820 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
12821 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
12822 caps = gst_caps_new_simple ("audio/x-raw",
12823 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
12824 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
12825 "non-interleaved" : "interleaved", NULL);
12830 if (flags & FLAG_IS_BIG_ENDIAN)
12831 format = GST_AUDIO_FORMAT_F64BE;
12833 format = GST_AUDIO_FORMAT_F64LE;
12835 if (flags & FLAG_IS_BIG_ENDIAN)
12836 format = GST_AUDIO_FORMAT_F32BE;
12838 format = GST_AUDIO_FORMAT_F32LE;
12840 caps = gst_caps_new_simple ("audio/x-raw",
12841 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
12842 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
12843 "non-interleaved" : "interleaved", NULL);
12847 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
12851 char *s, fourstr[5];
12853 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12854 s = g_strdup_printf ("audio/x-gst-fourcc-%s", g_strstrip (fourstr));
12855 caps = gst_caps_new_empty_simple (s);
12862 GstCaps *templ_caps =
12863 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
12864 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
12865 gst_caps_unref (caps);
12866 gst_caps_unref (templ_caps);
12867 caps = intersection;
12870 /* enable clipping for raw audio streams */
12871 s = gst_caps_get_structure (caps, 0);
12872 name = gst_structure_get_name (s);
12873 if (g_str_has_prefix (name, "audio/x-raw")) {
12874 stream->need_clip = TRUE;
12875 stream->max_buffer_size = 4096 * stream->bytes_per_frame;
12876 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
12882 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
12883 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
12887 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
12891 _codec ("DVD subtitle");
12892 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
12893 stream->need_process = TRUE;
12896 _codec ("Quicktime timed text");
12899 _codec ("3GPP timed text");
12901 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
12903 /* actual text piece needs to be extracted */
12904 stream->need_process = TRUE;
12907 _codec ("XML subtitles");
12908 caps = gst_caps_new_empty_simple ("application/ttml+xml");
12912 char *s, fourstr[5];
12914 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12915 s = g_strdup_printf ("text/x-gst-fourcc-%s", g_strstrip (fourstr));
12916 caps = gst_caps_new_empty_simple (s);
12925 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
12926 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
12932 _codec ("MPEG 1 video");
12933 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
12934 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12944 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
12945 const gchar * system_id)
12949 if (!qtdemux->protection_system_ids)
12950 qtdemux->protection_system_ids =
12951 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
12952 /* Check whether we already have an entry for this system ID. */
12953 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
12954 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
12955 if (g_ascii_strcasecmp (system_id, id) == 0) {
12959 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
12960 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,