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.
12 * Copyright (C) <2016> British Broadcasting Corporation
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Library General Public
16 * License as published by the Free Software Foundation; either
17 * version 2 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Library General Public License for more details.
24 * You should have received a copy of the GNU Library General Public
25 * License along with this library; if not, write to the
26 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
27 * Boston, MA 02110-1301, USA.
31 * SECTION:element-qtdemux
33 * Demuxes a .mov file into raw or compressed audio and/or video streams.
35 * This element supports both push and pull-based scheduling, depending on the
36 * capabilities of the upstream elements.
39 * <title>Example launch line</title>
41 * 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
42 * ]| Play (parse and decode) a .mov file and try to output it to
43 * an automatically detected soundcard and videosink. If the MOV file contains
44 * compressed audio or video data, this will only work if you have the
45 * right decoder elements/plugins installed.
53 #include "gst/gst-i18n-plugin.h"
55 #include <glib/gprintf.h>
56 #include <gst/tag/tag.h>
57 #include <gst/audio/audio.h>
58 #include <gst/video/video.h>
60 #include "qtatomparser.h"
61 #include "qtdemux_types.h"
62 #include "qtdemux_dump.h"
64 #include "descriptors.h"
65 #include "qtdemux_lang.h"
67 #include "qtpalette.h"
69 #include "gst/riff/riff-media.h"
70 #include "gst/riff/riff-read.h"
72 #include <gst/pbutils/pbutils.h>
79 #include <gst/math-compat.h>
85 /* max. size considered 'sane' for non-mdat atoms */
86 #define QTDEMUX_MAX_ATOM_SIZE (25*1024*1024)
88 /* if the sample index is larger than this, something is likely wrong */
89 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (50*1024*1024)
91 /* For converting qt creation times to unix epoch times */
92 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
93 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
94 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
95 QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
97 #define QTDEMUX_TREE_NODE_FOURCC(n) (QT_FOURCC(((guint8 *) (n)->data) + 4))
99 #define STREAM_IS_EOS(s) (s->time_position == GST_CLOCK_TIME_NONE)
101 #define ABSDIFF(x, y) ( (x) > (y) ? ((x) - (y)) : ((y) - (x)) )
103 GST_DEBUG_CATEGORY (qtdemux_debug);
105 typedef struct _QtDemuxSegment QtDemuxSegment;
106 typedef struct _QtDemuxSample QtDemuxSample;
108 typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo;
110 struct _QtDemuxSample
113 gint32 pts_offset; /* Add this value to timestamp to get the pts */
115 guint64 timestamp; /* DTS In mov time */
116 guint32 duration; /* In mov time */
117 gboolean keyframe; /* TRUE when this packet is a keyframe */
120 /* Macros for converting to/from timescale */
121 #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale))
122 #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND))
124 #define QTTIME_TO_GSTTIME(qtdemux, value) (gst_util_uint64_scale((value), GST_SECOND, (qtdemux)->timescale))
125 #define GSTTIME_TO_QTTIME(qtdemux, value) (gst_util_uint64_scale((value), (qtdemux)->timescale, GST_SECOND))
127 /* timestamp is the DTS */
128 #define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp))
129 /* timestamp + offset + cslg_shift is the outgoing PTS */
130 #define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (stream)->cslg_shift + (sample)->pts_offset))
131 /* timestamp + offset is the PTS used for internal seek calcuations */
132 #define QTSAMPLE_PTS_NO_CSLG(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (sample)->pts_offset))
133 /* timestamp + duration - dts is the duration */
134 #define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts))
136 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
139 * Quicktime has tracks and segments. A track is a continuous piece of
140 * multimedia content. The track is not always played from start to finish but
141 * instead, pieces of the track are 'cut out' and played in sequence. This is
142 * what the segments do.
144 * Inside the track we have keyframes (K) and delta frames. The track has its
145 * own timing, which starts from 0 and extends to end. The position in the track
146 * is called the media_time.
148 * The segments now describe the pieces that should be played from this track
149 * and are basically tuples of media_time/duration/rate entries. We can have
150 * multiple segments and they are all played after one another. An example:
152 * segment 1: media_time: 1 second, duration: 1 second, rate 1
153 * segment 2: media_time: 3 second, duration: 2 second, rate 2
155 * To correctly play back this track, one must play: 1 second of media starting
156 * from media_time 1 followed by 2 seconds of media starting from media_time 3
159 * Each of the segments will be played at a specific time, the first segment at
160 * time 0, the second one after the duration of the first one, etc.. Note that
161 * the time in resulting playback is not identical to the media_time of the
164 * Visually, assuming the track has 4 second of media_time:
167 * .-----------------------------------------------------------.
168 * track: | K.....K.........K........K.......K.......K...........K... |
169 * '-----------------------------------------------------------'
171 * .------------^ ^ .----------^ ^
172 * / .-------------' / .------------------'
174 * .--------------. .--------------.
175 * | segment 1 | | segment 2 |
176 * '--------------' '--------------'
178 * The challenge here is to cut out the right pieces of the track for each of
179 * the playback segments. This fortunately can easily be done with the SEGMENT
180 * events of GStreamer.
182 * For playback of segment 1, we need to provide the decoder with the keyframe
183 * (a), in the above figure, but we must instruct it only to output the decoded
184 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
185 * position set to the time of the segment: 0.
187 * We then proceed to push data from keyframe (a) to frame (b). The decoder
188 * decodes but clips all before media_time 1.
190 * After finishing a segment, we push out a new SEGMENT event with the clipping
191 * boundaries of the new data.
193 * This is a good usecase for the GStreamer accumulated SEGMENT events.
196 struct _QtDemuxSegment
198 /* global time and duration, all gst time */
200 GstClockTime stop_time;
201 GstClockTime duration;
202 /* media time of trak, all gst time */
203 GstClockTime media_start;
204 GstClockTime media_stop;
206 /* Media start time in trak timescale units */
207 guint32 trak_media_start;
210 #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
212 /* Used with fragmented MP4 files (mfra atom) */
217 } QtDemuxRandomAccessEntry;
219 typedef struct _QtDemuxStreamStsdEntry
230 /* Numerator/denominator framerate */
233 GstVideoColorimetry colorimetry;
234 guint16 bits_per_sample;
235 guint16 color_table_id;
236 GstMemory *rgb8_palette;
237 guint interlace_mode;
243 guint samples_per_packet;
244 guint samples_per_frame;
245 guint bytes_per_packet;
246 guint bytes_per_sample;
247 guint bytes_per_frame;
250 /* if we use chunks or samples */
254 } QtDemuxStreamStsdEntry;
256 #define CUR_STREAM(s) (&((s)->stsd_entries[(s)->cur_stsd_entry_index]))
258 struct _QtDemuxStream
262 QtDemuxStreamStsdEntry *stsd_entries;
263 guint stsd_entries_length;
264 guint cur_stsd_entry_index;
269 gboolean new_caps; /* If TRUE, caps need to be generated (by
270 * calling _configure_stream()) This happens
271 * for MSS and fragmented streams */
273 gboolean new_stream; /* signals that a stream_start is required */
274 gboolean on_keyframe; /* if this stream last pushed buffer was a
275 * keyframe. This is important to identify
276 * where to stop pushing buffers after a
277 * segment stop time */
279 /* if the stream has a redirect URI in its headers, we store it here */
286 guint64 duration; /* in timescale units */
290 gchar lang_id[4]; /* ISO 639-2T language code */
294 QtDemuxSample *samples;
295 gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */
296 guint32 first_duration; /* duration in timescale of first sample, used for figuring out
298 guint32 n_samples_moof; /* sample count in a moof */
299 guint64 duration_moof; /* duration in timescale of a moof, used for figure out
300 * the framerate of fragmented format stream */
301 guint64 duration_last_moof;
303 guint32 offset_in_sample; /* Offset in the current sample, used for
304 * streams which have got exceedingly big
305 * sample size (such as 24s of raw audio).
306 * Only used when max_buffer_size is non-NULL */
307 guint32 max_buffer_size; /* Maximum allowed size for output buffers.
308 * Currently only set for raw audio streams*/
316 gboolean use_allocator;
317 GstAllocator *allocator;
318 GstAllocationParams params;
322 /* when a discontinuity is pending */
325 /* list of buffers to push first */
328 /* if we need to clip this buffer. This is only needed for uncompressed
332 /* buffer needs some custom processing, e.g. subtitles */
333 gboolean need_process;
335 /* current position */
336 guint32 segment_index;
337 guint32 sample_index;
338 GstClockTime time_position; /* in gst time */
339 guint64 accumulated_base;
341 /* the Gst segment we are processing out, used for clipping */
344 /* quicktime segments */
346 QtDemuxSegment *segments;
347 gboolean dummy_segment;
352 GstTagList *stream_tags;
353 gboolean send_global_tags;
355 GstEvent *pending_event;
365 gboolean chunks_are_samples; /* TRUE means treat chunks as samples */
369 GstByteReader co_chunk;
371 guint32 current_chunk;
373 guint32 samples_per_chunk;
374 guint32 stsd_sample_description_id;
375 guint32 stco_sample_index;
377 guint32 sample_size; /* 0 means variable sizes are stored in stsz */
380 guint32 n_samples_per_chunk;
381 guint32 stsc_chunk_index;
382 guint32 stsc_sample_index;
383 guint64 chunk_offset;
386 guint32 stts_samples;
387 guint32 n_sample_times;
388 guint32 stts_sample_index;
390 guint32 stts_duration;
392 gboolean stss_present;
393 guint32 n_sample_syncs;
396 gboolean stps_present;
397 guint32 n_sample_partial_syncs;
399 QtDemuxRandomAccessEntry *ra_entries;
402 const QtDemuxRandomAccessEntry *pending_seek;
405 gboolean ctts_present;
406 guint32 n_composition_times;
408 guint32 ctts_sample_index;
416 gboolean parsed_trex;
417 guint32 def_sample_duration;
418 guint32 def_sample_size;
419 guint32 def_sample_flags;
423 /* stereoscopic video streams */
424 GstVideoMultiviewMode multiview_mode;
425 GstVideoMultiviewFlags multiview_flags;
427 /* protected streams */
429 guint32 protection_scheme_type;
430 guint32 protection_scheme_version;
431 gpointer protection_scheme_info; /* specific to the protection scheme */
432 GQueue protection_scheme_event_queue;
435 /* Contains properties and cryptographic info for a set of samples from a
436 * track protected using Common Encryption (cenc) */
437 struct _QtDemuxCencSampleSetInfo
439 GstStructure *default_properties;
441 /* @crypto_info holds one GstStructure per sample */
442 GPtrArray *crypto_info;
446 qt_demux_state_string (enum QtDemuxState state)
449 case QTDEMUX_STATE_INITIAL:
451 case QTDEMUX_STATE_HEADER:
453 case QTDEMUX_STATE_MOVIE:
455 case QTDEMUX_STATE_BUFFER_MDAT:
456 return "<BUFFER_MDAT>";
462 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
463 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
464 guint32 fourcc, GstByteReader * parser);
465 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
466 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
467 guint32 fourcc, GstByteReader * parser);
469 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
471 static GstStaticPadTemplate gst_qtdemux_sink_template =
472 GST_STATIC_PAD_TEMPLATE ("sink",
475 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
479 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
480 GST_STATIC_PAD_TEMPLATE ("video_%u",
483 GST_STATIC_CAPS_ANY);
485 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
486 GST_STATIC_PAD_TEMPLATE ("audio_%u",
489 GST_STATIC_CAPS_ANY);
491 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
492 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
495 GST_STATIC_CAPS_ANY);
497 #define gst_qtdemux_parent_class parent_class
498 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
500 static void gst_qtdemux_dispose (GObject * object);
503 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
504 GstClockTime media_time);
506 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
507 QtDemuxStream * str, gint64 media_offset);
510 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
511 static GstIndex *gst_qtdemux_get_index (GstElement * element);
513 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
514 GstStateChange transition);
515 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
516 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
517 GstObject * parent, GstPadMode mode, gboolean active);
519 static void gst_qtdemux_loop (GstPad * pad);
520 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
522 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
524 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
525 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
526 QtDemuxStream * stream);
527 static void gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
528 QtDemuxStream * stream);
529 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
532 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
533 const guint8 * buffer, guint length);
534 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
535 const guint8 * buffer, guint length);
536 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
537 static void qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist,
540 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
541 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, GNode * esds,
543 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
544 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
545 const guint8 * stsd_entry_data, gchar ** codec_name);
546 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
547 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
548 const guint8 * data, int len, gchar ** codec_name);
549 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
550 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
551 gchar ** codec_name);
552 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
553 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
554 const guint8 * stsd_entry_data, gchar ** codec_name);
556 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
557 QtDemuxStream * stream, guint32 n);
558 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
559 static void gst_qtdemux_stream_free (GstQTDemux * qtdemux,
560 QtDemuxStream * stream);
561 static void gst_qtdemux_stream_clear (GstQTDemux * qtdemux,
562 QtDemuxStream * stream);
563 static void gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int index);
564 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
565 static void qtdemux_do_allocation (GstQTDemux * qtdemux,
566 QtDemuxStream * stream);
567 static gboolean gst_qtdemux_activate_segment (GstQTDemux * qtdemux,
568 QtDemuxStream * stream, guint32 seg_idx, GstClockTime offset);
569 static gboolean gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux,
570 QtDemuxStream * stream, gint seg_idx, GstClockTime offset,
571 GstClockTime * _start, GstClockTime * _stop);
572 static void gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
573 QtDemuxStream * stream, gint segment_index, GstClockTime pos);
575 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
576 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
578 static gchar *qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes);
580 static GstStructure *qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
581 QtDemuxStream * stream, guint sample_index);
582 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
584 static void qtdemux_gst_structure_free (GstStructure * gststructure);
587 gst_qtdemux_class_init (GstQTDemuxClass * klass)
589 GObjectClass *gobject_class;
590 GstElementClass *gstelement_class;
592 gobject_class = (GObjectClass *) klass;
593 gstelement_class = (GstElementClass *) klass;
595 parent_class = g_type_class_peek_parent (klass);
597 gobject_class->dispose = gst_qtdemux_dispose;
599 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
601 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
602 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
605 gst_tag_register_musicbrainz_tags ();
607 gst_element_class_add_static_pad_template (gstelement_class,
608 &gst_qtdemux_sink_template);
609 gst_element_class_add_static_pad_template (gstelement_class,
610 &gst_qtdemux_videosrc_template);
611 gst_element_class_add_static_pad_template (gstelement_class,
612 &gst_qtdemux_audiosrc_template);
613 gst_element_class_add_static_pad_template (gstelement_class,
614 &gst_qtdemux_subsrc_template);
615 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
617 "Demultiplex a QuickTime file into audio and video streams",
618 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
620 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
625 gst_qtdemux_init (GstQTDemux * qtdemux)
628 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
629 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
630 gst_pad_set_activatemode_function (qtdemux->sinkpad,
631 qtdemux_sink_activate_mode);
632 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
633 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
634 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
636 qtdemux->state = QTDEMUX_STATE_INITIAL;
637 qtdemux->pullbased = FALSE;
638 qtdemux->posted_redirect = FALSE;
639 qtdemux->neededbytes = 16;
641 qtdemux->adapter = gst_adapter_new ();
643 qtdemux->first_mdat = -1;
644 qtdemux->got_moov = FALSE;
645 qtdemux->mdatoffset = -1;
646 qtdemux->mdatbuffer = NULL;
647 qtdemux->restoredata_buffer = NULL;
648 qtdemux->restoredata_offset = -1;
649 qtdemux->fragment_start = -1;
650 qtdemux->fragment_start_offset = -1;
651 qtdemux->media_caps = NULL;
652 qtdemux->exposed = FALSE;
653 qtdemux->mss_mode = FALSE;
654 qtdemux->pending_newsegment = NULL;
655 qtdemux->upstream_format_is_time = FALSE;
656 qtdemux->have_group_id = FALSE;
657 qtdemux->group_id = G_MAXUINT;
658 qtdemux->cenc_aux_info_offset = 0;
659 qtdemux->cenc_aux_info_sizes = NULL;
660 qtdemux->cenc_aux_sample_count = 0;
661 qtdemux->protection_system_ids = NULL;
662 g_queue_init (&qtdemux->protection_event_queue);
663 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
664 qtdemux->tag_list = gst_tag_list_new_empty ();
665 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
666 qtdemux->flowcombiner = gst_flow_combiner_new ();
668 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
672 gst_qtdemux_dispose (GObject * object)
674 GstQTDemux *qtdemux = GST_QTDEMUX (object);
676 if (qtdemux->adapter) {
677 g_object_unref (G_OBJECT (qtdemux->adapter));
678 qtdemux->adapter = NULL;
680 gst_tag_list_unref (qtdemux->tag_list);
681 gst_flow_combiner_free (qtdemux->flowcombiner);
682 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
684 g_queue_clear (&qtdemux->protection_event_queue);
686 g_free (qtdemux->cenc_aux_info_sizes);
687 qtdemux->cenc_aux_info_sizes = NULL;
689 G_OBJECT_CLASS (parent_class)->dispose (object);
693 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
695 if (qtdemux->posted_redirect) {
696 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
697 (_("This file contains no playable streams.")),
698 ("no known streams found, a redirect message has been posted"));
700 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
701 (_("This file contains no playable streams.")),
702 ("no known streams found"));
707 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
709 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
710 mem, size, 0, size, mem, free_func);
714 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
721 if (G_UNLIKELY (size == 0)) {
723 GstBuffer *tmp = NULL;
725 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
726 if (ret != GST_FLOW_OK)
729 gst_buffer_map (tmp, &map, GST_MAP_READ);
730 size = QT_UINT32 (map.data);
731 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
733 gst_buffer_unmap (tmp, &map);
734 gst_buffer_unref (tmp);
737 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
738 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
739 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
740 /* we're pulling header but already got most interesting bits,
741 * so never mind the rest (e.g. tags) (that much) */
742 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
746 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
747 (_("This file is invalid and cannot be played.")),
748 ("atom has bogus size %" G_GUINT64_FORMAT, size));
749 return GST_FLOW_ERROR;
753 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
755 if (G_UNLIKELY (flow != GST_FLOW_OK))
758 bsize = gst_buffer_get_size (*buf);
759 /* Catch short reads - we don't want any partial atoms */
760 if (G_UNLIKELY (bsize < size)) {
761 GST_WARNING_OBJECT (qtdemux,
762 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
763 gst_buffer_unref (*buf);
773 gst_qtdemux_src_convert (GstQTDemux * qtdemux, GstPad * pad,
774 GstFormat src_format, gint64 src_value, GstFormat dest_format,
778 QtDemuxStream *stream = gst_pad_get_element_private (pad);
781 if (stream->subtype != FOURCC_vide) {
786 switch (src_format) {
787 case GST_FORMAT_TIME:
788 switch (dest_format) {
789 case GST_FORMAT_BYTES:{
790 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
796 *dest_value = stream->samples[index].offset;
798 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
799 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
800 GST_TIME_ARGS (src_value), *dest_value);
808 case GST_FORMAT_BYTES:
809 switch (dest_format) {
810 case GST_FORMAT_TIME:{
812 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
821 QTSTREAMTIME_TO_GSTTIME (stream,
822 stream->samples[index].timestamp);
823 GST_DEBUG_OBJECT (qtdemux,
824 "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
825 GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
844 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
846 gboolean res = FALSE;
848 *duration = GST_CLOCK_TIME_NONE;
850 if (qtdemux->duration != 0 &&
851 qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
852 *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
855 *duration = GST_CLOCK_TIME_NONE;
862 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
865 gboolean res = FALSE;
866 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
868 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
870 switch (GST_QUERY_TYPE (query)) {
871 case GST_QUERY_POSITION:{
874 gst_query_parse_position (query, &fmt, NULL);
875 if (fmt == GST_FORMAT_TIME
876 && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
877 gst_query_set_position (query, GST_FORMAT_TIME,
878 qtdemux->segment.position);
883 case GST_QUERY_DURATION:{
886 gst_query_parse_duration (query, &fmt, NULL);
887 if (fmt == GST_FORMAT_TIME) {
888 /* First try to query upstream */
889 res = gst_pad_query_default (pad, parent, query);
891 GstClockTime duration;
892 if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
893 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
900 case GST_QUERY_CONVERT:{
901 GstFormat src_fmt, dest_fmt;
902 gint64 src_value, dest_value = 0;
904 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
906 res = gst_qtdemux_src_convert (qtdemux, pad,
907 src_fmt, src_value, dest_fmt, &dest_value);
909 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
914 case GST_QUERY_FORMATS:
915 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
918 case GST_QUERY_SEEKING:{
922 /* try upstream first */
923 res = gst_pad_query_default (pad, parent, query);
926 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
927 if (fmt == GST_FORMAT_TIME) {
928 GstClockTime duration;
930 gst_qtdemux_get_duration (qtdemux, &duration);
932 if (!qtdemux->pullbased) {
935 /* we might be able with help from upstream */
937 q = gst_query_new_seeking (GST_FORMAT_BYTES);
938 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
939 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
940 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
944 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
950 case GST_QUERY_SEGMENT:
955 format = qtdemux->segment.format;
958 gst_segment_to_stream_time (&qtdemux->segment, format,
959 qtdemux->segment.start);
960 if ((stop = qtdemux->segment.stop) == -1)
961 stop = qtdemux->segment.duration;
963 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
965 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
970 res = gst_pad_query_default (pad, parent, query);
978 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
980 if (G_LIKELY (stream->pad)) {
981 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
982 GST_DEBUG_PAD_NAME (stream->pad));
984 if (!gst_tag_list_is_empty (stream->stream_tags)) {
985 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
986 stream->stream_tags);
987 gst_pad_push_event (stream->pad,
988 gst_event_new_tag (gst_tag_list_ref (stream->stream_tags)));
991 if (G_UNLIKELY (stream->send_global_tags)) {
992 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
994 gst_pad_push_event (stream->pad,
995 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
996 stream->send_global_tags = FALSE;
1001 /* push event on all source pads; takes ownership of the event */
1003 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
1006 gboolean has_valid_stream = FALSE;
1007 GstEventType etype = GST_EVENT_TYPE (event);
1009 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
1010 GST_EVENT_TYPE_NAME (event));
1012 for (n = 0; n < qtdemux->n_streams; n++) {
1014 QtDemuxStream *stream = qtdemux->streams[n];
1015 GST_DEBUG_OBJECT (qtdemux, "pushing on pad %i", n);
1017 if ((pad = stream->pad)) {
1018 has_valid_stream = TRUE;
1020 if (etype == GST_EVENT_EOS) {
1021 /* let's not send twice */
1022 if (stream->sent_eos)
1024 stream->sent_eos = TRUE;
1027 gst_pad_push_event (pad, gst_event_ref (event));
1031 gst_event_unref (event);
1033 /* if it is EOS and there are no pads, post an error */
1034 if (!has_valid_stream && etype == GST_EVENT_EOS) {
1035 gst_qtdemux_post_no_playable_stream_error (qtdemux);
1039 /* push a pending newsegment event, if any from the streaming thread */
1041 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
1043 if (qtdemux->pending_newsegment) {
1044 gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
1045 qtdemux->pending_newsegment = NULL;
1055 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
1057 if ((gint64) s1->timestamp + s1->pts_offset > *media_time)
1059 if ((gint64) s1->timestamp + s1->pts_offset == *media_time)
1065 /* find the index of the sample that includes the data for @media_time using a
1066 * binary search. Only to be called in optimized cases of linear search below.
1068 * Returns the index of the sample.
1071 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
1074 QtDemuxSample *result;
1077 /* convert media_time to mov format */
1079 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1081 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
1082 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
1083 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
1085 if (G_LIKELY (result))
1086 index = result - str->samples;
1095 /* find the index of the sample that includes the data for @media_offset using a
1098 * Returns the index of the sample.
1101 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
1102 QtDemuxStream * str, gint64 media_offset)
1104 QtDemuxSample *result = str->samples;
1107 if (result == NULL || str->n_samples == 0)
1110 if (media_offset == result->offset)
1114 while (index < str->n_samples - 1) {
1115 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1118 if (media_offset < result->offset)
1129 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1134 /* find the index of the sample that includes the data for @media_time using a
1135 * linear search, and keeping in mind that not all samples may have been parsed
1136 * yet. If possible, it will delegate to binary search.
1138 * Returns the index of the sample.
1141 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
1142 GstClockTime media_time)
1146 QtDemuxSample *sample;
1148 /* convert media_time to mov format */
1150 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1152 sample = str->samples;
1153 if (mov_time == sample->timestamp + sample->pts_offset)
1156 /* use faster search if requested time in already parsed range */
1157 sample = str->samples + str->stbl_index;
1158 if (str->stbl_index >= 0 &&
1159 mov_time <= (sample->timestamp + sample->pts_offset))
1160 return gst_qtdemux_find_index (qtdemux, str, media_time);
1162 while (index < str->n_samples - 1) {
1163 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1166 sample = str->samples + index + 1;
1167 if (mov_time < (sample->timestamp + sample->pts_offset))
1177 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1182 /* find the index of the keyframe needed to decode the sample at @index
1183 * of stream @str, or of a subsequent keyframe (depending on @next)
1185 * Returns the index of the keyframe.
1188 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1189 guint32 index, gboolean next)
1191 guint32 new_index = index;
1193 if (index >= str->n_samples) {
1194 new_index = str->n_samples;
1198 /* all keyframes, return index */
1199 if (str->all_keyframe) {
1204 /* else search until we have a keyframe */
1205 while (new_index < str->n_samples) {
1206 if (next && !qtdemux_parse_samples (qtdemux, str, new_index))
1209 if (str->samples[new_index].keyframe)
1221 if (new_index == str->n_samples) {
1222 GST_DEBUG_OBJECT (qtdemux, "no next keyframe");
1227 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index %s index %u "
1228 "gave %u", next ? "after" : "before", index, new_index);
1235 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", new_index);
1240 /* find the segment for @time_position for @stream
1242 * Returns the index of the segment containing @time_position.
1243 * Returns the last segment and sets the @eos variable to TRUE
1244 * if the time is beyond the end. @eos may be NULL
1247 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1248 GstClockTime time_position)
1253 GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1254 GST_TIME_ARGS (time_position));
1257 for (i = 0; i < stream->n_segments; i++) {
1258 QtDemuxSegment *segment = &stream->segments[i];
1260 GST_LOG_OBJECT (stream->pad,
1261 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1262 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1264 /* For the last segment we include stop_time in the last segment */
1265 if (i < stream->n_segments - 1) {
1266 if (segment->time <= time_position && time_position < segment->stop_time) {
1267 GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1272 /* Last segment always matches */
1280 /* move the stream @str to the sample position @index.
1282 * Updates @str->sample_index and marks discontinuity if needed.
1285 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1288 /* no change needed */
1289 if (index == str->sample_index)
1292 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1295 /* position changed, we have a discont */
1296 str->sample_index = index;
1297 str->offset_in_sample = 0;
1298 /* Each time we move in the stream we store the position where we are
1300 str->from_sample = index;
1301 str->discont = TRUE;
1305 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1306 gboolean use_sparse, gboolean next, gint64 * key_time, gint64 * key_offset)
1309 gint64 min_byte_offset = -1;
1312 min_offset = desired_time;
1314 /* for each stream, find the index of the sample in the segment
1315 * and move back to the previous keyframe. */
1316 for (n = 0; n < qtdemux->n_streams; n++) {
1318 guint32 index, kindex;
1320 GstClockTime media_start;
1321 GstClockTime media_time;
1322 GstClockTime seg_time;
1323 QtDemuxSegment *seg;
1324 gboolean empty_segment = FALSE;
1326 str = qtdemux->streams[n];
1328 if (CUR_STREAM (str)->sparse && !use_sparse)
1331 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1332 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1334 /* get segment and time in the segment */
1335 seg = &str->segments[seg_idx];
1336 seg_time = (desired_time - seg->time) * seg->rate;
1338 while (QTSEGMENT_IS_EMPTY (seg)) {
1340 empty_segment = TRUE;
1341 GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1344 if (seg_idx == str->n_segments)
1346 seg = &str->segments[seg_idx];
1349 if (seg_idx == str->n_segments) {
1350 /* FIXME track shouldn't have the last segment as empty, but if it
1351 * happens we better handle it */
1355 /* get the media time in the segment */
1356 media_start = seg->media_start + seg_time;
1358 /* get the index of the sample with media time */
1359 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1360 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1361 " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1362 GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1365 /* shift to next frame if we are looking for next keyframe */
1366 if (next && QTSAMPLE_PTS_NO_CSLG (str, &str->samples[index]) < media_start
1367 && index < str->stbl_index)
1370 if (!empty_segment) {
1371 /* find previous keyframe */
1372 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, next);
1374 /* we will settle for one before if none found after */
1375 if (next && kindex == -1)
1376 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
1378 /* if the keyframe is at a different position, we need to update the
1379 * requested seek time */
1380 if (index != kindex) {
1383 /* get timestamp of keyframe */
1384 media_time = QTSAMPLE_PTS_NO_CSLG (str, &str->samples[kindex]);
1385 GST_DEBUG_OBJECT (qtdemux,
1386 "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1387 G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1388 str->samples[kindex].offset);
1390 /* keyframes in the segment get a chance to change the
1391 * desired_offset. keyframes out of the segment are
1393 if (media_time >= seg->media_start) {
1394 GstClockTime seg_time;
1396 /* this keyframe is inside the segment, convert back to
1398 seg_time = (media_time - seg->media_start) + seg->time;
1399 if ((!next && (seg_time < min_offset)) ||
1400 (next && (seg_time > min_offset)))
1401 min_offset = seg_time;
1406 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1407 min_byte_offset = str->samples[index].offset;
1411 *key_time = min_offset;
1413 *key_offset = min_byte_offset;
1417 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1418 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1422 g_return_val_if_fail (format != NULL, FALSE);
1423 g_return_val_if_fail (cur != NULL, FALSE);
1424 g_return_val_if_fail (stop != NULL, FALSE);
1426 if (*format == GST_FORMAT_TIME)
1430 if (cur_type != GST_SEEK_TYPE_NONE)
1431 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1432 if (res && stop_type != GST_SEEK_TYPE_NONE)
1433 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1436 *format = GST_FORMAT_TIME;
1441 /* perform seek in push based mode:
1442 find BYTE position to move to based on time and delegate to upstream
1445 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1450 GstSeekType cur_type, stop_type;
1451 gint64 cur, stop, key_cur;
1454 gint64 original_stop;
1457 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1459 gst_event_parse_seek (event, &rate, &format, &flags,
1460 &cur_type, &cur, &stop_type, &stop);
1461 seqnum = gst_event_get_seqnum (event);
1463 /* only forward streaming and seeking is possible */
1465 goto unsupported_seek;
1467 /* convert to TIME if needed and possible */
1468 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1472 /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1473 * the original stop position to use when upstream pushes the new segment
1475 original_stop = stop;
1478 /* find reasonable corresponding BYTE position,
1479 * also try to mind about keyframes, since we can not go back a bit for them
1481 /* determining @next here based on SNAP_BEFORE/SNAP_AFTER should
1482 * mostly just work, but let's not yet boldly go there ... */
1483 gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, FALSE, &key_cur, &byte_cur);
1488 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1489 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1492 GST_OBJECT_LOCK (qtdemux);
1493 qtdemux->seek_offset = byte_cur;
1494 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1495 qtdemux->push_seek_start = cur;
1497 qtdemux->push_seek_start = key_cur;
1500 if (stop_type == GST_SEEK_TYPE_NONE) {
1501 qtdemux->push_seek_stop = qtdemux->segment.stop;
1503 qtdemux->push_seek_stop = original_stop;
1505 GST_OBJECT_UNLOCK (qtdemux);
1507 /* BYTE seek event */
1508 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1510 gst_event_set_seqnum (event, seqnum);
1511 res = gst_pad_push_event (qtdemux->sinkpad, event);
1518 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1524 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1529 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1534 /* perform the seek.
1536 * We set all segment_indexes in the streams to unknown and
1537 * adjust the time_position to the desired position. this is enough
1538 * to trigger a segment switch in the streaming thread to start
1539 * streaming from the desired position.
1541 * Keyframe seeking is a little more complicated when dealing with
1542 * segments. Ideally we want to move to the previous keyframe in
1543 * the segment but there might not be a keyframe in the segment. In
1544 * fact, none of the segments could contain a keyframe. We take a
1545 * practical approach: seek to the previous keyframe in the segment,
1546 * if there is none, seek to the beginning of the segment.
1548 * Called with STREAM_LOCK
1551 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1552 guint32 seqnum, GstSeekFlags flags)
1554 gint64 desired_offset;
1557 desired_offset = segment->position;
1559 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1560 GST_TIME_ARGS (desired_offset));
1562 /* may not have enough fragmented info to do this adjustment,
1563 * and we can't scan (and probably should not) at this time with
1564 * possibly flushing upstream */
1565 if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1567 gboolean next, before, after;
1569 before = ! !(flags & GST_SEEK_FLAG_SNAP_BEFORE);
1570 after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER);
1571 next = after && !before;
1572 if (segment->rate < 0)
1575 gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, next, &min_offset,
1577 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1578 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1579 desired_offset = min_offset;
1582 /* and set all streams to the final position */
1583 gst_flow_combiner_reset (qtdemux->flowcombiner);
1584 qtdemux->segment_seqnum = seqnum;
1585 for (n = 0; n < qtdemux->n_streams; n++) {
1586 QtDemuxStream *stream = qtdemux->streams[n];
1588 stream->time_position = desired_offset;
1589 stream->accumulated_base = 0;
1590 stream->sample_index = -1;
1591 stream->offset_in_sample = 0;
1592 stream->segment_index = -1;
1593 stream->sent_eos = FALSE;
1595 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1596 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1598 segment->position = desired_offset;
1599 segment->time = desired_offset;
1600 if (segment->rate >= 0) {
1601 segment->start = desired_offset;
1603 /* we stop at the end */
1604 if (segment->stop == -1)
1605 segment->stop = segment->duration;
1607 segment->stop = desired_offset;
1610 if (qtdemux->fragmented)
1611 qtdemux->fragmented_seek_pending = TRUE;
1616 /* do a seek in pull based mode */
1618 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1623 GstSeekType cur_type, stop_type;
1627 GstSegment seeksegment;
1629 GstEvent *flush_event;
1632 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1634 gst_event_parse_seek (event, &rate, &format, &flags,
1635 &cur_type, &cur, &stop_type, &stop);
1636 seqnum = gst_event_get_seqnum (event);
1638 /* we have to have a format as the segment format. Try to convert
1640 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1644 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1646 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1650 flush = flags & GST_SEEK_FLAG_FLUSH;
1652 /* stop streaming, either by flushing or by pausing the task */
1654 flush_event = gst_event_new_flush_start ();
1656 gst_event_set_seqnum (flush_event, seqnum);
1657 /* unlock upstream pull_range */
1658 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1659 /* make sure out loop function exits */
1660 gst_qtdemux_push_event (qtdemux, flush_event);
1662 /* non flushing seek, pause the task */
1663 gst_pad_pause_task (qtdemux->sinkpad);
1666 /* wait for streaming to finish */
1667 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1669 /* copy segment, we need this because we still need the old
1670 * segment when we close the current segment. */
1671 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1674 /* configure the segment with the seek variables */
1675 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1676 gst_segment_do_seek (&seeksegment, rate, format, flags,
1677 cur_type, cur, stop_type, stop, &update);
1680 /* now do the seek, this actually never returns FALSE */
1681 gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1683 /* prepare for streaming again */
1685 flush_event = gst_event_new_flush_stop (TRUE);
1687 gst_event_set_seqnum (flush_event, seqnum);
1689 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1690 gst_qtdemux_push_event (qtdemux, flush_event);
1693 /* commit the new segment */
1694 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1696 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1697 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1698 qtdemux->segment.format, qtdemux->segment.position);
1700 gst_message_set_seqnum (msg, seqnum);
1701 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1704 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1705 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1706 qtdemux->sinkpad, NULL);
1708 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1715 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1721 qtdemux_ensure_index (GstQTDemux * qtdemux)
1725 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1727 /* Build complete index */
1728 for (i = 0; i < qtdemux->n_streams; i++) {
1729 QtDemuxStream *stream = qtdemux->streams[i];
1731 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1739 GST_LOG_OBJECT (qtdemux,
1740 "Building complete index of stream %u for seeking failed!", i);
1746 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1749 gboolean res = TRUE;
1750 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1752 switch (GST_EVENT_TYPE (event)) {
1753 case GST_EVENT_SEEK:
1755 #ifndef GST_DISABLE_GST_DEBUG
1756 GstClockTime ts = gst_util_get_timestamp ();
1758 guint32 seqnum = gst_event_get_seqnum (event);
1760 if (seqnum == qtdemux->segment_seqnum) {
1761 GST_LOG_OBJECT (pad,
1762 "Drop duplicated SEEK event seqnum %" G_GUINT32_FORMAT, seqnum);
1763 gst_event_unref (event);
1767 if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1768 /* seek should be handled by upstream, we might need to re-download fragments */
1769 GST_DEBUG_OBJECT (qtdemux,
1770 "let upstream handle seek for fragmented playback");
1774 /* Build complete index for seeking;
1775 * if not a fragmented file at least */
1776 if (!qtdemux->fragmented)
1777 if (!qtdemux_ensure_index (qtdemux))
1779 #ifndef GST_DISABLE_GST_DEBUG
1780 ts = gst_util_get_timestamp () - ts;
1781 GST_INFO_OBJECT (qtdemux,
1782 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1785 if (qtdemux->pullbased) {
1786 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1787 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1788 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1790 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams
1791 && !qtdemux->fragmented) {
1792 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1794 GST_DEBUG_OBJECT (qtdemux,
1795 "ignoring seek in push mode in current state");
1798 gst_event_unref (event);
1802 res = gst_pad_event_default (pad, parent, event);
1812 GST_ERROR_OBJECT (qtdemux, "Index failed");
1813 gst_event_unref (event);
1819 /* stream/index return sample that is min/max w.r.t. byte position,
1820 * time is min/max w.r.t. time of samples,
1821 * the latter need not be time of the former sample */
1823 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1824 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1827 gint64 time, min_time;
1828 QtDemuxStream *stream;
1834 for (n = 0; n < qtdemux->n_streams; ++n) {
1837 gboolean set_sample;
1839 str = qtdemux->streams[n];
1846 i = str->n_samples - 1;
1850 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1851 if (str->samples[i].size == 0)
1854 if (fw && (str->samples[i].offset < byte_pos))
1857 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1860 /* move stream to first available sample */
1862 gst_qtdemux_move_stream (qtdemux, str, i);
1866 /* avoid index from sparse streams since they might be far away */
1867 if (!CUR_STREAM (str)->sparse) {
1868 /* determine min/max time */
1869 time = QTSAMPLE_PTS (str, &str->samples[i]);
1870 if (min_time == -1 || (!fw && time > min_time) ||
1871 (fw && time < min_time)) {
1875 /* determine stream with leading sample, to get its position */
1877 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1878 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1886 /* no sample for this stream, mark eos */
1888 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1899 static QtDemuxStream *
1900 _create_stream (void)
1902 QtDemuxStream *stream;
1904 stream = g_new0 (QtDemuxStream, 1);
1905 /* new streams always need a discont */
1906 stream->discont = TRUE;
1907 /* we enable clipping for raw audio/video streams */
1908 stream->need_clip = FALSE;
1909 stream->need_process = FALSE;
1910 stream->segment_index = -1;
1911 stream->time_position = 0;
1912 stream->sample_index = -1;
1913 stream->offset_in_sample = 0;
1914 stream->new_stream = TRUE;
1915 stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1916 stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1917 stream->protected = FALSE;
1918 stream->protection_scheme_type = 0;
1919 stream->protection_scheme_version = 0;
1920 stream->protection_scheme_info = NULL;
1921 stream->n_samples_moof = 0;
1922 stream->duration_moof = 0;
1923 stream->duration_last_moof = 0;
1924 stream->alignment = 1;
1925 stream->stream_tags = gst_tag_list_new_empty ();
1926 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
1927 g_queue_init (&stream->protection_scheme_event_queue);
1932 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1934 GstStructure *structure;
1935 const gchar *variant;
1936 const GstCaps *mediacaps = NULL;
1938 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1940 structure = gst_caps_get_structure (caps, 0);
1941 variant = gst_structure_get_string (structure, "variant");
1943 if (variant && strcmp (variant, "mss-fragmented") == 0) {
1944 QtDemuxStream *stream;
1945 const GValue *value;
1947 demux->fragmented = TRUE;
1948 demux->mss_mode = TRUE;
1950 if (demux->n_streams > 1) {
1951 /* can't do this, we can only renegotiate for another mss format */
1955 value = gst_structure_get_value (structure, "media-caps");
1958 const GValue *timescale_v;
1960 /* TODO update when stream changes during playback */
1962 if (demux->n_streams == 0) {
1963 stream = _create_stream ();
1964 demux->streams[demux->n_streams] = stream;
1965 demux->n_streams = 1;
1967 stream = demux->streams[0];
1970 timescale_v = gst_structure_get_value (structure, "timescale");
1972 stream->timescale = g_value_get_uint64 (timescale_v);
1974 /* default mss timescale */
1975 stream->timescale = 10000000;
1977 demux->timescale = stream->timescale;
1979 mediacaps = gst_value_get_caps (value);
1980 if (!CUR_STREAM (stream)->caps
1981 || !gst_caps_is_equal_fixed (mediacaps, CUR_STREAM (stream)->caps)) {
1982 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1984 stream->new_caps = TRUE;
1986 gst_caps_replace (&CUR_STREAM (stream)->caps, (GstCaps *) mediacaps);
1987 structure = gst_caps_get_structure (mediacaps, 0);
1988 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
1989 stream->subtype = FOURCC_vide;
1991 gst_structure_get_int (structure, "width", &CUR_STREAM (stream)->width);
1992 gst_structure_get_int (structure, "height",
1993 &CUR_STREAM (stream)->height);
1994 gst_structure_get_fraction (structure, "framerate",
1995 &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
1996 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
1998 stream->subtype = FOURCC_soun;
1999 gst_structure_get_int (structure, "channels",
2000 &CUR_STREAM (stream)->n_channels);
2001 gst_structure_get_int (structure, "rate", &rate);
2002 CUR_STREAM (stream)->rate = rate;
2005 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
2007 demux->mss_mode = FALSE;
2014 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
2018 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
2019 gst_pad_stop_task (qtdemux->sinkpad);
2021 if (hard || qtdemux->upstream_format_is_time) {
2022 qtdemux->state = QTDEMUX_STATE_INITIAL;
2023 qtdemux->neededbytes = 16;
2024 qtdemux->todrop = 0;
2025 qtdemux->pullbased = FALSE;
2026 qtdemux->posted_redirect = FALSE;
2027 qtdemux->first_mdat = -1;
2028 qtdemux->header_size = 0;
2029 qtdemux->mdatoffset = -1;
2030 qtdemux->restoredata_offset = -1;
2031 if (qtdemux->mdatbuffer)
2032 gst_buffer_unref (qtdemux->mdatbuffer);
2033 if (qtdemux->restoredata_buffer)
2034 gst_buffer_unref (qtdemux->restoredata_buffer);
2035 qtdemux->mdatbuffer = NULL;
2036 qtdemux->restoredata_buffer = NULL;
2037 qtdemux->mdatleft = 0;
2038 qtdemux->mdatsize = 0;
2039 if (qtdemux->comp_brands)
2040 gst_buffer_unref (qtdemux->comp_brands);
2041 qtdemux->comp_brands = NULL;
2042 qtdemux->last_moov_offset = -1;
2043 if (qtdemux->moov_node_compressed) {
2044 g_node_destroy (qtdemux->moov_node_compressed);
2045 if (qtdemux->moov_node)
2046 g_free (qtdemux->moov_node->data);
2048 qtdemux->moov_node_compressed = NULL;
2049 if (qtdemux->moov_node)
2050 g_node_destroy (qtdemux->moov_node);
2051 qtdemux->moov_node = NULL;
2052 if (qtdemux->tag_list)
2053 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
2054 qtdemux->tag_list = gst_tag_list_new_empty ();
2055 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
2057 if (qtdemux->element_index)
2058 gst_object_unref (qtdemux->element_index);
2059 qtdemux->element_index = NULL;
2061 qtdemux->major_brand = 0;
2062 if (qtdemux->pending_newsegment)
2063 gst_event_unref (qtdemux->pending_newsegment);
2064 qtdemux->pending_newsegment = NULL;
2065 qtdemux->upstream_format_is_time = FALSE;
2066 qtdemux->upstream_seekable = FALSE;
2067 qtdemux->upstream_size = 0;
2069 qtdemux->fragment_start = -1;
2070 qtdemux->fragment_start_offset = -1;
2071 qtdemux->duration = 0;
2072 qtdemux->moof_offset = 0;
2073 qtdemux->chapters_track_id = 0;
2074 qtdemux->have_group_id = FALSE;
2075 qtdemux->group_id = G_MAXUINT;
2077 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
2079 g_queue_clear (&qtdemux->protection_event_queue);
2081 qtdemux->offset = 0;
2082 gst_adapter_clear (qtdemux->adapter);
2083 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
2084 qtdemux->segment_seqnum = 0;
2087 for (n = 0; n < qtdemux->n_streams; n++) {
2088 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
2089 qtdemux->streams[n] = NULL;
2091 qtdemux->n_streams = 0;
2092 qtdemux->n_video_streams = 0;
2093 qtdemux->n_audio_streams = 0;
2094 qtdemux->n_sub_streams = 0;
2095 qtdemux->exposed = FALSE;
2096 qtdemux->fragmented = FALSE;
2097 qtdemux->mss_mode = FALSE;
2098 gst_caps_replace (&qtdemux->media_caps, NULL);
2099 qtdemux->timescale = 0;
2100 qtdemux->got_moov = FALSE;
2101 if (qtdemux->protection_system_ids) {
2102 g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2103 qtdemux->protection_system_ids = NULL;
2105 } else if (qtdemux->mss_mode) {
2106 gst_flow_combiner_reset (qtdemux->flowcombiner);
2107 for (n = 0; n < qtdemux->n_streams; n++)
2108 gst_qtdemux_stream_clear (qtdemux, qtdemux->streams[n]);
2110 gst_flow_combiner_reset (qtdemux->flowcombiner);
2111 for (n = 0; n < qtdemux->n_streams; n++) {
2112 qtdemux->streams[n]->sent_eos = FALSE;
2113 qtdemux->streams[n]->time_position = 0;
2114 qtdemux->streams[n]->accumulated_base = 0;
2116 if (!qtdemux->pending_newsegment) {
2117 qtdemux->pending_newsegment = gst_event_new_segment (&qtdemux->segment);
2118 if (qtdemux->segment_seqnum)
2119 gst_event_set_seqnum (qtdemux->pending_newsegment,
2120 qtdemux->segment_seqnum);
2126 /* Maps the @segment to the qt edts internal segments and pushes
2127 * the correspnding segment event.
2129 * If it ends up being at a empty segment, a gap will be pushed and the next
2130 * edts segment will be activated in sequence.
2132 * To be used in push-mode only */
2134 gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
2138 for (n = 0; n < qtdemux->n_streams; n++) {
2139 QtDemuxStream *stream = qtdemux->streams[n];
2141 stream->time_position = segment->start;
2143 /* in push mode we should be guaranteed that we will have empty segments
2144 * at the beginning and then one segment after, other scenarios are not
2145 * supported and are discarded when parsing the edts */
2146 for (i = 0; i < stream->n_segments; i++) {
2147 if (stream->segments[i].stop_time > segment->start) {
2148 gst_qtdemux_activate_segment (qtdemux, stream, i,
2149 stream->time_position);
2150 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
2151 /* push the empty segment and move to the next one */
2152 gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
2153 stream->time_position);
2157 g_assert (i == stream->n_segments - 1);
2164 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2167 GstQTDemux *demux = GST_QTDEMUX (parent);
2168 gboolean res = TRUE;
2170 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2172 switch (GST_EVENT_TYPE (event)) {
2173 case GST_EVENT_SEGMENT:
2176 QtDemuxStream *stream;
2180 /* some debug output */
2181 gst_event_copy_segment (event, &segment);
2182 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2185 /* erase any previously set segment */
2186 gst_event_replace (&demux->pending_newsegment, NULL);
2188 if (segment.format == GST_FORMAT_TIME) {
2189 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
2190 gst_event_replace (&demux->pending_newsegment, event);
2191 demux->upstream_format_is_time = TRUE;
2193 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2194 "not in time format");
2196 /* chain will send initial newsegment after pads have been added */
2197 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
2198 GST_DEBUG_OBJECT (demux, "still starting, eating event");
2203 /* check if this matches a time seek we received previously
2204 * FIXME for backwards compatibility reasons we use the
2205 * seek_offset here to compare. In the future we might want to
2206 * change this to use the seqnum as it uniquely should identify
2207 * the segment that corresponds to the seek. */
2208 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2209 ", received segment offset %" G_GINT64_FORMAT,
2210 demux->seek_offset, segment.start);
2211 if (segment.format == GST_FORMAT_BYTES
2212 && demux->seek_offset == segment.start) {
2213 GST_OBJECT_LOCK (demux);
2214 offset = segment.start;
2216 segment.format = GST_FORMAT_TIME;
2217 segment.start = demux->push_seek_start;
2218 segment.stop = demux->push_seek_stop;
2219 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2220 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2221 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2222 GST_OBJECT_UNLOCK (demux);
2225 /* we only expect a BYTE segment, e.g. following a seek */
2226 if (segment.format == GST_FORMAT_BYTES) {
2227 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2228 offset = segment.start;
2230 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2231 NULL, (gint64 *) & segment.start);
2232 if ((gint64) segment.start < 0)
2235 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2236 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2237 NULL, (gint64 *) & segment.stop);
2238 /* keyframe seeking should already arrange for start >= stop,
2239 * but make sure in other rare cases */
2240 segment.stop = MAX (segment.stop, segment.start);
2242 } else if (segment.format == GST_FORMAT_TIME) {
2243 /* push all data on the adapter before starting this
2245 gst_qtdemux_process_adapter (demux, TRUE);
2247 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2251 /* We shouldn't modify upstream driven TIME FORMAT segment */
2252 if (!demux->upstream_format_is_time) {
2253 /* accept upstream's notion of segment and distribute along */
2254 segment.format = GST_FORMAT_TIME;
2255 segment.position = segment.time = segment.start;
2256 segment.duration = demux->segment.duration;
2257 segment.base = gst_segment_to_running_time (&demux->segment,
2258 GST_FORMAT_TIME, demux->segment.position);
2261 gst_segment_copy_into (&segment, &demux->segment);
2262 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2264 /* map segment to internal qt segments and push on each stream */
2265 if (demux->n_streams) {
2266 if (demux->fragmented) {
2267 GstEvent *segment_event = gst_event_new_segment (&segment);
2269 gst_event_replace (&demux->pending_newsegment, NULL);
2270 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
2271 gst_qtdemux_push_event (demux, segment_event);
2273 gst_event_replace (&demux->pending_newsegment, NULL);
2274 gst_qtdemux_map_and_push_segments (demux, &segment);
2278 /* clear leftover in current segment, if any */
2279 gst_adapter_clear (demux->adapter);
2281 /* set up streaming thread */
2282 demux->offset = offset;
2283 if (demux->upstream_format_is_time) {
2284 GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2285 "set values to restart reading from a new atom");
2286 demux->neededbytes = 16;
2289 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2292 demux->todrop = stream->samples[idx].offset - offset;
2293 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2295 /* set up for EOS */
2296 demux->neededbytes = -1;
2301 gst_event_unref (event);
2305 case GST_EVENT_FLUSH_START:
2307 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2308 gst_event_unref (event);
2313 case GST_EVENT_FLUSH_STOP:
2317 dur = demux->segment.duration;
2318 gst_qtdemux_reset (demux, FALSE);
2319 demux->segment.duration = dur;
2321 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2322 gst_event_unref (event);
2328 /* If we are in push mode, and get an EOS before we've seen any streams,
2329 * then error out - we have nowhere to send the EOS */
2330 if (!demux->pullbased) {
2332 gboolean has_valid_stream = FALSE;
2333 for (i = 0; i < demux->n_streams; i++) {
2334 if (demux->streams[i]->pad != NULL) {
2335 has_valid_stream = TRUE;
2339 if (!has_valid_stream)
2340 gst_qtdemux_post_no_playable_stream_error (demux);
2342 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2343 (guint) gst_adapter_available (demux->adapter));
2344 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2350 case GST_EVENT_CAPS:{
2351 GstCaps *caps = NULL;
2353 gst_event_parse_caps (event, &caps);
2354 gst_qtdemux_setcaps (demux, caps);
2356 gst_event_unref (event);
2359 case GST_EVENT_PROTECTION:
2361 const gchar *system_id = NULL;
2363 gst_event_parse_protection (event, &system_id, NULL, NULL);
2364 GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2366 gst_qtdemux_append_protection_system_id (demux, system_id);
2367 /* save the event for later, for source pads that have not been created */
2368 g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2369 /* send it to all pads that already exist */
2370 gst_qtdemux_push_event (demux, event);
2378 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2386 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2388 GstQTDemux *demux = GST_QTDEMUX (element);
2390 GST_OBJECT_LOCK (demux);
2391 if (demux->element_index)
2392 gst_object_unref (demux->element_index);
2394 demux->element_index = gst_object_ref (index);
2396 demux->element_index = NULL;
2398 GST_OBJECT_UNLOCK (demux);
2399 /* object lock might be taken again */
2401 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2402 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2403 demux->element_index, demux->index_id);
2407 gst_qtdemux_get_index (GstElement * element)
2409 GstIndex *result = NULL;
2410 GstQTDemux *demux = GST_QTDEMUX (element);
2412 GST_OBJECT_LOCK (demux);
2413 if (demux->element_index)
2414 result = gst_object_ref (demux->element_index);
2415 GST_OBJECT_UNLOCK (demux);
2417 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2424 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2426 g_free ((gpointer) stream->stco.data);
2427 stream->stco.data = NULL;
2428 g_free ((gpointer) stream->stsz.data);
2429 stream->stsz.data = NULL;
2430 g_free ((gpointer) stream->stsc.data);
2431 stream->stsc.data = NULL;
2432 g_free ((gpointer) stream->stts.data);
2433 stream->stts.data = NULL;
2434 g_free ((gpointer) stream->stss.data);
2435 stream->stss.data = NULL;
2436 g_free ((gpointer) stream->stps.data);
2437 stream->stps.data = NULL;
2438 g_free ((gpointer) stream->ctts.data);
2439 stream->ctts.data = NULL;
2443 gst_qtdemux_stream_flush_segments_data (GstQTDemux * qtdemux,
2444 QtDemuxStream * stream)
2446 g_free (stream->segments);
2447 stream->segments = NULL;
2448 stream->segment_index = -1;
2449 stream->accumulated_base = 0;
2453 gst_qtdemux_stream_flush_samples_data (GstQTDemux * qtdemux,
2454 QtDemuxStream * stream)
2456 g_free (stream->samples);
2457 stream->samples = NULL;
2458 gst_qtdemux_stbl_free (stream);
2461 g_free (stream->ra_entries);
2462 stream->ra_entries = NULL;
2463 stream->n_ra_entries = 0;
2465 stream->sample_index = -1;
2466 stream->stbl_index = -1;
2467 stream->n_samples = 0;
2468 stream->time_position = 0;
2470 stream->n_samples_moof = 0;
2471 stream->duration_moof = 0;
2472 stream->duration_last_moof = 0;
2476 gst_qtdemux_stream_clear (GstQTDemux * qtdemux, QtDemuxStream * stream)
2479 if (stream->allocator)
2480 gst_object_unref (stream->allocator);
2481 while (stream->buffers) {
2482 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2483 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2485 for (i = 0; i < stream->stsd_entries_length; i++) {
2486 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2487 if (entry->rgb8_palette) {
2488 gst_memory_unref (entry->rgb8_palette);
2489 entry->rgb8_palette = NULL;
2491 entry->sparse = FALSE;
2494 gst_tag_list_unref (stream->stream_tags);
2495 stream->stream_tags = gst_tag_list_new_empty ();
2496 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
2497 g_free (stream->redirect_uri);
2498 stream->redirect_uri = NULL;
2499 stream->sent_eos = FALSE;
2500 stream->protected = FALSE;
2501 if (stream->protection_scheme_info) {
2502 if (stream->protection_scheme_type == FOURCC_cenc) {
2503 QtDemuxCencSampleSetInfo *info =
2504 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2505 if (info->default_properties)
2506 gst_structure_free (info->default_properties);
2507 if (info->crypto_info)
2508 g_ptr_array_free (info->crypto_info, TRUE);
2510 g_free (stream->protection_scheme_info);
2511 stream->protection_scheme_info = NULL;
2513 stream->protection_scheme_type = 0;
2514 stream->protection_scheme_version = 0;
2515 g_queue_foreach (&stream->protection_scheme_event_queue,
2516 (GFunc) gst_event_unref, NULL);
2517 g_queue_clear (&stream->protection_scheme_event_queue);
2518 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
2519 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
2523 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
2526 gst_qtdemux_stream_clear (qtdemux, stream);
2527 for (i = 0; i < stream->stsd_entries_length; i++) {
2528 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2530 gst_caps_unref (entry->caps);
2534 gst_tag_list_unref (stream->stream_tags);
2536 gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
2537 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, stream->pad);
2543 gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int i)
2545 g_assert (i >= 0 && i < qtdemux->n_streams && qtdemux->streams[i] != NULL);
2547 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[i]);
2548 qtdemux->streams[i] = qtdemux->streams[qtdemux->n_streams - 1];
2549 qtdemux->streams[qtdemux->n_streams - 1] = NULL;
2550 qtdemux->n_streams--;
2553 static GstStateChangeReturn
2554 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2556 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2557 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2559 switch (transition) {
2560 case GST_STATE_CHANGE_PAUSED_TO_READY:
2566 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2568 switch (transition) {
2569 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2570 gst_qtdemux_reset (qtdemux, TRUE);
2581 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2583 /* counts as header data */
2584 qtdemux->header_size += length;
2586 /* only consider at least a sufficiently complete ftyp atom */
2590 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2591 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2592 GST_FOURCC_ARGS (qtdemux->major_brand));
2593 if (qtdemux->comp_brands)
2594 gst_buffer_unref (qtdemux->comp_brands);
2595 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2596 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2601 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist,
2602 GstTagList * xmptaglist)
2604 /* Strip out bogus fields */
2606 if (gst_tag_list_get_scope (taglist) == GST_TAG_SCOPE_GLOBAL) {
2607 gst_tag_list_remove_tag (xmptaglist, GST_TAG_VIDEO_CODEC);
2608 gst_tag_list_remove_tag (xmptaglist, GST_TAG_AUDIO_CODEC);
2610 gst_tag_list_remove_tag (xmptaglist, GST_TAG_CONTAINER_FORMAT);
2613 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, xmptaglist);
2615 /* prioritize native tags using _KEEP mode */
2616 gst_tag_list_insert (taglist, xmptaglist, GST_TAG_MERGE_KEEP);
2617 gst_tag_list_unref (xmptaglist);
2622 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
2630 QtDemuxStream *stream;
2631 GstStructure *structure;
2632 QtDemuxCencSampleSetInfo *ss_info = NULL;
2633 const gchar *system_id;
2634 gboolean uses_sub_sample_encryption = FALSE;
2636 if (qtdemux->n_streams == 0)
2639 stream = qtdemux->streams[0];
2641 structure = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
2642 if (!gst_structure_has_name (structure, "application/x-cenc")) {
2643 GST_WARNING_OBJECT (qtdemux,
2644 "Attempting PIFF box parsing on an unencrypted stream.");
2648 gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
2649 G_TYPE_STRING, &system_id, NULL);
2650 gst_qtdemux_append_protection_system_id (qtdemux, system_id);
2652 stream->protected = TRUE;
2653 stream->protection_scheme_type = FOURCC_cenc;
2655 if (!stream->protection_scheme_info)
2656 stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
2658 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2660 if (ss_info->default_properties)
2661 gst_structure_free (ss_info->default_properties);
2663 ss_info->default_properties =
2664 gst_structure_new ("application/x-cenc",
2665 "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE, NULL);
2667 if (ss_info->crypto_info) {
2668 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
2669 g_ptr_array_free (ss_info->crypto_info, TRUE);
2670 ss_info->crypto_info = NULL;
2674 gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
2676 if (!gst_byte_reader_get_uint8 (&br, &version)) {
2677 GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
2681 if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
2682 GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
2686 if ((flags & 0x000001)) {
2687 guint32 algorithm_id = 0;
2690 gboolean is_encrypted = TRUE;
2692 if (!gst_byte_reader_get_uint24_le (&br, &algorithm_id)) {
2693 GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
2698 if (algorithm_id == 0) {
2699 is_encrypted = FALSE;
2700 } else if (algorithm_id == 1) {
2701 /* FIXME: maybe store this in properties? */
2702 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
2703 } else if (algorithm_id == 2) {
2704 /* FIXME: maybe store this in properties? */
2705 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
2708 if (!gst_byte_reader_get_uint8 (&br, &iv_size))
2711 if (!gst_byte_reader_get_data (&br, 16, &kid))
2714 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
2715 gst_buffer_fill (kid_buf, 0, kid, 16);
2716 if (ss_info->default_properties)
2717 gst_structure_free (ss_info->default_properties);
2718 ss_info->default_properties =
2719 gst_structure_new ("application/x-cenc",
2720 "iv_size", G_TYPE_UINT, iv_size,
2721 "encrypted", G_TYPE_BOOLEAN, is_encrypted,
2722 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
2723 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
2724 "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
2725 gst_buffer_unref (kid_buf);
2726 } else if ((flags & 0x000002)) {
2727 uses_sub_sample_encryption = TRUE;
2730 if (!gst_byte_reader_get_uint32_be (&br, &qtdemux->cenc_aux_sample_count)) {
2731 GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
2735 ss_info->crypto_info =
2736 g_ptr_array_new_full (qtdemux->cenc_aux_sample_count,
2737 (GDestroyNotify) qtdemux_gst_structure_free);
2739 for (i = 0; i < qtdemux->cenc_aux_sample_count; ++i) {
2740 GstStructure *properties;
2744 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
2745 if (properties == NULL) {
2746 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
2750 if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
2751 GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
2752 gst_structure_free (properties);
2755 buf = gst_buffer_new_wrapped (data, iv_size);
2756 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
2757 gst_buffer_unref (buf);
2759 if (uses_sub_sample_encryption) {
2760 guint16 n_subsamples;
2762 if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
2763 || n_subsamples == 0) {
2764 GST_ERROR_OBJECT (qtdemux,
2765 "failed to get subsample count for sample %u", i);
2766 gst_structure_free (properties);
2769 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
2770 if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
2771 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
2773 gst_structure_free (properties);
2776 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
2777 gst_structure_set (properties,
2778 "subsample_count", G_TYPE_UINT, n_subsamples,
2779 "subsamples", GST_TYPE_BUFFER, buf, NULL);
2780 gst_buffer_unref (buf);
2782 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
2785 g_ptr_array_add (ss_info->crypto_info, properties);
2790 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2792 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2793 0x97, 0xA9, 0x42, 0xE8,
2794 0x9C, 0x71, 0x99, 0x94,
2795 0x91, 0xE3, 0xAF, 0xAC
2797 static const guint8 playready_uuid[] = {
2798 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2799 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2802 static const guint8 piff_sample_encryption_uuid[] = {
2803 0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
2804 0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
2809 /* counts as header data */
2810 qtdemux->header_size += length;
2812 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2814 if (length <= offset + 16) {
2815 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2819 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2821 GstTagList *taglist;
2823 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2824 length - offset - 16, NULL);
2825 taglist = gst_tag_list_from_xmp_buffer (buf);
2826 gst_buffer_unref (buf);
2828 /* make sure we have a usable taglist */
2829 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
2831 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
2833 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
2835 const gunichar2 *s_utf16;
2838 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
2839 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
2840 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
2841 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
2845 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
2846 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
2848 } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
2849 qtdemux_parse_piff (qtdemux, buffer, length, offset);
2851 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
2852 GST_READ_UINT32_LE (buffer + offset),
2853 GST_READ_UINT32_LE (buffer + offset + 4),
2854 GST_READ_UINT32_LE (buffer + offset + 8),
2855 GST_READ_UINT32_LE (buffer + offset + 12));
2860 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2862 GstSidxParser sidx_parser;
2863 GstIsoffParserResult res;
2866 gst_isoff_qt_sidx_parser_init (&sidx_parser);
2869 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
2871 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
2872 if (res == GST_ISOFF_QT_PARSER_DONE) {
2873 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
2875 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
2878 /* caller verifies at least 8 bytes in buf */
2880 extract_initial_length_and_fourcc (const guint8 * data, guint size,
2881 guint64 * plength, guint32 * pfourcc)
2886 length = QT_UINT32 (data);
2887 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2888 fourcc = QT_FOURCC (data + 4);
2889 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
2892 length = G_MAXUINT64;
2893 } else if (length == 1 && size >= 16) {
2894 /* this means we have an extended size, which is the 64 bit value of
2895 * the next 8 bytes */
2896 length = QT_UINT64 (data + 8);
2897 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2907 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
2909 guint32 version = 0;
2910 GstClockTime duration = 0;
2912 if (!gst_byte_reader_get_uint32_be (br, &version))
2917 if (!gst_byte_reader_get_uint64_be (br, &duration))
2922 if (!gst_byte_reader_get_uint32_be (br, &dur))
2927 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
2928 qtdemux->duration = duration;
2934 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
2940 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
2941 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
2943 if (!stream->parsed_trex && qtdemux->moov_node) {
2945 GstByteReader trex_data;
2947 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
2949 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
2952 guint32 id = 0, dur = 0, size = 0, flags = 0, dummy = 0;
2954 /* skip version/flags */
2955 if (!gst_byte_reader_skip (&trex_data, 4))
2957 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
2959 if (id != stream->track_id)
2961 /* sample description index; ignore */
2962 if (!gst_byte_reader_get_uint32_be (&trex_data, &dummy))
2964 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2966 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
2968 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
2971 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
2972 "duration %d, size %d, flags 0x%x", stream->track_id,
2975 stream->parsed_trex = TRUE;
2976 stream->def_sample_duration = dur;
2977 stream->def_sample_size = size;
2978 stream->def_sample_flags = flags;
2981 /* iterate all siblings */
2982 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
2988 *ds_duration = stream->def_sample_duration;
2989 *ds_size = stream->def_sample_size;
2990 *ds_flags = stream->def_sample_flags;
2992 /* even then, above values are better than random ... */
2993 if (G_UNLIKELY (!stream->parsed_trex)) {
2994 GST_WARNING_OBJECT (qtdemux,
2995 "failed to find fragment defaults for stream %d", stream->track_id);
3002 /* This method should be called whenever a more accurate duration might
3003 * have been found. It will update all relevant variables if/where needed
3006 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
3010 GstClockTime prevdur;
3012 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
3014 if (movdur > qtdemux->duration) {
3015 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
3016 GST_DEBUG_OBJECT (qtdemux,
3017 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
3018 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
3019 qtdemux->duration = movdur;
3020 GST_DEBUG_OBJECT (qtdemux,
3021 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
3022 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
3023 GST_TIME_ARGS (qtdemux->segment.stop));
3024 if (qtdemux->segment.duration == prevdur) {
3025 /* If the current segment has duration/stop identical to previous duration
3026 * update them also (because they were set at that point in time with
3027 * the wrong duration */
3028 /* We convert the value *from* the timescale version to avoid rounding errors */
3029 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
3030 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
3031 qtdemux->segment.duration = fixeddur;
3032 qtdemux->segment.stop = fixeddur;
3035 for (i = 0; i < qtdemux->n_streams; i++) {
3036 QtDemuxStream *stream = qtdemux->streams[i];
3038 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
3039 if (movdur > stream->duration) {
3040 GST_DEBUG_OBJECT (qtdemux,
3041 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
3042 GST_TIME_ARGS (duration));
3043 stream->duration = movdur;
3044 if (stream->dummy_segment) {
3045 /* Update all dummy values to new duration */
3046 stream->segments[0].stop_time = duration;
3047 stream->segments[0].duration = duration;
3048 stream->segments[0].media_stop = duration;
3050 /* let downstream know we possibly have a new stop time */
3051 if (stream->segment_index != -1) {
3054 if (qtdemux->segment.rate >= 0) {
3055 pos = stream->segment.start;
3057 pos = stream->segment.stop;
3060 gst_qtdemux_stream_update_segment (qtdemux, stream,
3061 stream->segment_index, pos, NULL, NULL);
3070 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
3071 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
3072 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
3073 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts,
3076 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
3078 gint32 data_offset = 0;
3079 guint32 flags = 0, first_flags = 0, samples_count = 0;
3082 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
3083 QtDemuxSample *sample;
3084 gboolean ismv = FALSE;
3085 gint64 initial_offset;
3087 GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
3088 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
3089 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
3090 d_sample_size, d_sample_flags, *base_offset, decode_ts);
3092 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
3093 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
3097 /* presence of stss or not can't really tell us much,
3098 * and flags and so on tend to be marginally reliable in these files */
3099 if (stream->subtype == FOURCC_soun) {
3100 GST_DEBUG_OBJECT (qtdemux,
3101 "sound track in fragmented file; marking all keyframes");
3102 stream->all_keyframe = TRUE;
3105 if (!gst_byte_reader_skip (trun, 1) ||
3106 !gst_byte_reader_get_uint24_be (trun, &flags))
3109 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3112 if (flags & TR_DATA_OFFSET) {
3113 /* note this is really signed */
3114 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3116 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3117 /* default base offset = first byte of moof */
3118 if (*base_offset == -1) {
3119 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3120 *base_offset = moof_offset;
3122 *running_offset = *base_offset + data_offset;
3124 /* if no offset at all, that would mean data starts at moof start,
3125 * which is a bit wrong and is ismv crappy way, so compensate
3126 * assuming data is in mdat following moof */
3127 if (*base_offset == -1) {
3128 *base_offset = moof_offset + moof_length + 8;
3129 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3132 if (*running_offset == -1)
3133 *running_offset = *base_offset;
3136 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3138 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3139 data_offset, flags, samples_count);
3141 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3142 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3143 GST_DEBUG_OBJECT (qtdemux,
3144 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3145 flags ^= TR_FIRST_SAMPLE_FLAGS;
3147 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3149 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3153 /* FIXME ? spec says other bits should also be checked to determine
3154 * entry size (and prefix size for that matter) */
3156 dur_offset = size_offset = 0;
3157 if (flags & TR_SAMPLE_DURATION) {
3158 GST_LOG_OBJECT (qtdemux, "entry duration present");
3159 dur_offset = entry_size;
3162 if (flags & TR_SAMPLE_SIZE) {
3163 GST_LOG_OBJECT (qtdemux, "entry size present");
3164 size_offset = entry_size;
3167 if (flags & TR_SAMPLE_FLAGS) {
3168 GST_LOG_OBJECT (qtdemux, "entry flags present");
3169 flags_offset = entry_size;
3172 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3173 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3174 ct_offset = entry_size;
3178 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3180 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3182 if (stream->n_samples + samples_count >=
3183 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3186 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3187 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3188 (stream->n_samples + samples_count) *
3189 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3191 /* create a new array of samples if it's the first sample parsed */
3192 if (stream->n_samples == 0) {
3193 g_assert (stream->samples == NULL);
3194 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3195 /* or try to reallocate it with space enough to insert the new samples */
3197 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3198 stream->n_samples + samples_count);
3199 if (stream->samples == NULL)
3202 if (qtdemux->fragment_start != -1) {
3203 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3204 qtdemux->fragment_start = -1;
3206 if (stream->n_samples == 0) {
3207 if (decode_ts > 0) {
3208 timestamp = decode_ts;
3209 } else if (stream->pending_seek != NULL) {
3210 /* if we don't have a timestamp from a tfdt box, we'll use the one
3211 * from the mfra seek table */
3212 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3213 GST_TIME_ARGS (stream->pending_seek->ts));
3215 /* FIXME: this is not fully correct, the timestamp refers to the random
3216 * access sample refered to in the tfra entry, which may not necessarily
3217 * be the first sample in the tfrag/trun (but hopefully/usually is) */
3218 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3223 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3224 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3225 GST_TIME_ARGS (gst_ts));
3227 /* subsequent fragments extend stream */
3229 stream->samples[stream->n_samples - 1].timestamp +
3230 stream->samples[stream->n_samples - 1].duration;
3232 /* If this is a GST_FORMAT_BYTES stream and there's a significant
3233 * difference (1 sec.) between decode_ts and timestamp, prefer the
3235 if (has_tfdt && !qtdemux->upstream_format_is_time
3236 && ABSDIFF (decode_ts, timestamp) >
3237 MAX (stream->duration_last_moof / 2,
3238 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) {
3239 GST_INFO_OBJECT (qtdemux,
3240 "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT
3241 ") are significantly different (more than %" GST_TIME_FORMAT
3242 "), using decode_ts",
3243 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)),
3244 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)),
3245 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
3246 MAX (stream->duration_last_moof / 2,
3247 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND)))));
3248 timestamp = decode_ts;
3251 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3252 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3253 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3257 initial_offset = *running_offset;
3259 sample = stream->samples + stream->n_samples;
3260 for (i = 0; i < samples_count; i++) {
3261 guint32 dur, size, sflags, ct;
3263 /* first read sample data */
3264 if (flags & TR_SAMPLE_DURATION) {
3265 dur = QT_UINT32 (data + dur_offset);
3267 dur = d_sample_duration;
3269 if (flags & TR_SAMPLE_SIZE) {
3270 size = QT_UINT32 (data + size_offset);
3272 size = d_sample_size;
3274 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3276 sflags = first_flags;
3278 sflags = d_sample_flags;
3280 } else if (flags & TR_SAMPLE_FLAGS) {
3281 sflags = QT_UINT32 (data + flags_offset);
3283 sflags = d_sample_flags;
3285 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3286 ct = QT_UINT32 (data + ct_offset);
3292 /* fill the sample information */
3293 sample->offset = *running_offset;
3294 sample->pts_offset = ct;
3295 sample->size = size;
3296 sample->timestamp = timestamp;
3297 sample->duration = dur;
3298 /* sample-is-difference-sample */
3299 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3300 * now idea how it relates to bitfield other than massive LE/BE confusion */
3301 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3302 *running_offset += size;
3304 stream->duration_moof += dur;
3308 /* Update total duration if needed */
3309 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3311 /* Pre-emptively figure out size of mdat based on trun information.
3312 * If the [mdat] atom is effectivelly read, it will be replaced by the actual
3313 * size, else we will still be able to use this when dealing with gap'ed
3315 qtdemux->mdatleft = *running_offset - initial_offset;
3316 qtdemux->mdatoffset = initial_offset;
3317 qtdemux->mdatsize = qtdemux->mdatleft;
3319 stream->n_samples += samples_count;
3320 stream->n_samples_moof += samples_count;
3322 if (stream->pending_seek != NULL)
3323 stream->pending_seek = NULL;
3329 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3334 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3340 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3341 "be larger than %uMB (broken file?)", stream->n_samples,
3342 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3347 /* find stream with @id */
3348 static inline QtDemuxStream *
3349 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3351 QtDemuxStream *stream;
3355 if (G_UNLIKELY (!id)) {
3356 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3360 /* try to get it fast and simple */
3361 if (G_LIKELY (id <= qtdemux->n_streams)) {
3362 stream = qtdemux->streams[id - 1];
3363 if (G_LIKELY (stream->track_id == id))
3367 /* linear search otherwise */
3368 for (i = 0; i < qtdemux->n_streams; i++) {
3369 stream = qtdemux->streams[i];
3370 if (stream->track_id == id)
3373 if (qtdemux->mss_mode) {
3374 /* mss should have only 1 stream anyway */
3375 return qtdemux->streams[0];
3382 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3383 guint32 * fragment_number)
3385 if (!gst_byte_reader_skip (mfhd, 4))
3387 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3392 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3398 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3399 QtDemuxStream ** stream, guint32 * default_sample_duration,
3400 guint32 * default_sample_size, guint32 * default_sample_flags,
3401 gint64 * base_offset)
3404 guint32 track_id = 0;
3406 if (!gst_byte_reader_skip (tfhd, 1) ||
3407 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3410 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3413 *stream = qtdemux_find_stream (qtdemux, track_id);
3414 if (G_UNLIKELY (!*stream))
3415 goto unknown_stream;
3417 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3418 *base_offset = qtdemux->moof_offset;
3420 if (flags & TF_BASE_DATA_OFFSET)
3421 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3424 /* obtain stream defaults */
3425 qtdemux_parse_trex (qtdemux, *stream,
3426 default_sample_duration, default_sample_size, default_sample_flags);
3428 /* FIXME: Handle TF_SAMPLE_DESCRIPTION_INDEX properly */
3429 if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
3430 if (!gst_byte_reader_skip (tfhd, 4))
3433 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3434 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3437 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3438 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3441 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3442 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3449 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3454 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
3460 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3461 guint64 * decode_time)
3463 guint32 version = 0;
3465 if (!gst_byte_reader_get_uint32_be (br, &version))
3470 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3473 guint32 dec_time = 0;
3474 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3476 *decode_time = dec_time;
3479 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3486 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3491 /* Returns a pointer to a GstStructure containing the properties of
3492 * the stream sample identified by @sample_index. The caller must unref
3493 * the returned object after use. Returns NULL if unsuccessful. */
3494 static GstStructure *
3495 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3496 QtDemuxStream * stream, guint sample_index)
3498 QtDemuxCencSampleSetInfo *info = NULL;
3500 g_return_val_if_fail (stream != NULL, NULL);
3501 g_return_val_if_fail (stream->protected, NULL);
3502 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3504 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3506 /* Currently, cenc properties for groups of samples are not supported, so
3507 * simply return a copy of the default sample properties */
3508 return gst_structure_copy (info->default_properties);
3511 /* Parses the sizes of sample auxiliary information contained within a stream,
3512 * as given in a saiz box. Returns array of sample_count guint8 size values,
3513 * or NULL on failure */
3515 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3516 GstByteReader * br, guint32 * sample_count)
3520 guint8 default_info_size;
3522 g_return_val_if_fail (qtdemux != NULL, NULL);
3523 g_return_val_if_fail (stream != NULL, NULL);
3524 g_return_val_if_fail (br != NULL, NULL);
3525 g_return_val_if_fail (sample_count != NULL, NULL);
3527 if (!gst_byte_reader_get_uint32_be (br, &flags))
3531 /* aux_info_type and aux_info_type_parameter are ignored */
3532 if (!gst_byte_reader_skip (br, 8))
3536 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3538 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3540 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3542 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3545 if (default_info_size == 0) {
3546 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3550 info_sizes = g_new (guint8, *sample_count);
3551 memset (info_sizes, default_info_size, *sample_count);
3557 /* Parses the offset of sample auxiliary information contained within a stream,
3558 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3560 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3561 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3566 guint32 aux_info_type = 0;
3567 guint32 aux_info_type_parameter = 0;
3568 guint32 entry_count;
3571 const guint8 *aux_info_type_data = NULL;
3573 g_return_val_if_fail (qtdemux != NULL, FALSE);
3574 g_return_val_if_fail (stream != NULL, FALSE);
3575 g_return_val_if_fail (br != NULL, FALSE);
3576 g_return_val_if_fail (offset != NULL, FALSE);
3578 if (!gst_byte_reader_get_uint8 (br, &version))
3581 if (!gst_byte_reader_get_uint24_be (br, &flags))
3586 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3588 aux_info_type = QT_FOURCC (aux_info_type_data);
3590 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3592 } else if (stream->protected) {
3593 aux_info_type = stream->protection_scheme_type;
3595 aux_info_type = CUR_STREAM (stream)->fourcc;
3599 *info_type = aux_info_type;
3600 if (info_type_parameter)
3601 *info_type_parameter = aux_info_type_parameter;
3603 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3604 "aux_info_type_parameter: %#06x",
3605 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3607 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3610 if (entry_count != 1) {
3611 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3616 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3618 *offset = (guint64) off_32;
3620 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3625 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3630 qtdemux_gst_structure_free (GstStructure * gststructure)
3633 gst_structure_free (gststructure);
3637 /* Parses auxiliary information relating to samples protected using Common
3638 * Encryption (cenc); the format of this information is defined in
3639 * ISO/IEC 23001-7. Returns TRUE if successful; FALSE otherwise. */
3641 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3642 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3644 QtDemuxCencSampleSetInfo *ss_info = NULL;
3647 GPtrArray *old_crypto_info = NULL;
3648 guint old_entries = 0;
3650 g_return_val_if_fail (qtdemux != NULL, FALSE);
3651 g_return_val_if_fail (stream != NULL, FALSE);
3652 g_return_val_if_fail (br != NULL, FALSE);
3653 g_return_val_if_fail (stream->protected, FALSE);
3654 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3656 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3658 if (ss_info->crypto_info) {
3659 old_crypto_info = ss_info->crypto_info;
3660 /* Count number of non-null entries remaining at the tail end */
3661 for (i = old_crypto_info->len - 1; i >= 0; i--) {
3662 if (g_ptr_array_index (old_crypto_info, i) == NULL)
3668 ss_info->crypto_info =
3669 g_ptr_array_new_full (sample_count + old_entries,
3670 (GDestroyNotify) qtdemux_gst_structure_free);
3672 /* We preserve old entries because we parse the next moof in advance
3673 * of consuming all samples from the previous moof, and otherwise
3674 * we'd discard the corresponding crypto info for the samples
3675 * from the previous fragment. */
3677 GST_DEBUG_OBJECT (qtdemux, "Preserving %d old crypto info entries",
3679 for (i = old_crypto_info->len - old_entries; i < old_crypto_info->len; i++) {
3680 g_ptr_array_add (ss_info->crypto_info, g_ptr_array_index (old_crypto_info,
3682 g_ptr_array_index (old_crypto_info, i) = NULL;
3686 if (old_crypto_info) {
3687 /* Everything now belongs to the new array */
3688 g_ptr_array_free (old_crypto_info, TRUE);
3691 for (i = 0; i < sample_count; ++i) {
3692 GstStructure *properties;
3693 guint16 n_subsamples = 0;
3698 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3699 if (properties == NULL) {
3700 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3703 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3704 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3705 gst_structure_free (properties);
3708 if (!gst_byte_reader_dup_data (br, iv_size, &data)) {
3709 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3710 gst_structure_free (properties);
3713 buf = gst_buffer_new_wrapped (data, iv_size);
3714 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3715 gst_buffer_unref (buf);
3716 size = info_sizes[i];
3717 if (size > iv_size) {
3718 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3719 || !(n_subsamples > 0)) {
3720 gst_structure_free (properties);
3721 GST_ERROR_OBJECT (qtdemux,
3722 "failed to get subsample count for sample %u", i);
3725 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3726 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3727 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3729 gst_structure_free (properties);
3732 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3734 gst_structure_free (properties);
3737 gst_structure_set (properties,
3738 "subsample_count", G_TYPE_UINT, n_subsamples,
3739 "subsamples", GST_TYPE_BUFFER, buf, NULL);
3740 gst_buffer_unref (buf);
3742 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3744 g_ptr_array_add (ss_info->crypto_info, properties);
3749 /* Converts a UUID in raw byte form to a string representation, as defined in
3750 * RFC 4122. The caller takes ownership of the returned string and is
3751 * responsible for freeing it after use. */
3753 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3755 const guint8 *uuid = (const guint8 *) uuid_bytes;
3757 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3758 "%02x%02x-%02x%02x%02x%02x%02x%02x",
3759 uuid[0], uuid[1], uuid[2], uuid[3],
3760 uuid[4], uuid[5], uuid[6], uuid[7],
3761 uuid[8], uuid[9], uuid[10], uuid[11],
3762 uuid[12], uuid[13], uuid[14], uuid[15]);
3765 /* Parses a Protection System Specific Header box (pssh), as defined in the
3766 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3767 * information needed by a specific content protection system in order to
3768 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3771 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
3773 gchar *sysid_string;
3774 guint32 pssh_size = QT_UINT32 (node->data);
3775 GstBuffer *pssh = NULL;
3776 GstEvent *event = NULL;
3777 guint32 parent_box_type;
3780 if (G_UNLIKELY (pssh_size < 32U)) {
3781 GST_ERROR_OBJECT (qtdemux, "invalid box size");
3786 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
3788 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
3790 pssh = gst_buffer_new_wrapped (g_memdup (node->data, pssh_size), pssh_size);
3791 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
3792 gst_buffer_get_size (pssh));
3794 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
3796 /* Push an event containing the pssh box onto the queues of all streams. */
3797 event = gst_event_new_protection (sysid_string, pssh,
3798 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
3799 for (i = 0; i < qtdemux->n_streams; ++i) {
3800 g_queue_push_tail (&qtdemux->streams[i]->protection_scheme_event_queue,
3801 gst_event_ref (event));
3803 g_free (sysid_string);
3804 gst_event_unref (event);
3805 gst_buffer_unref (pssh);
3810 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
3811 guint64 moof_offset, QtDemuxStream * stream)
3813 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
3815 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
3816 GNode *saiz_node, *saio_node, *pssh_node;
3817 GstByteReader saiz_data, saio_data;
3818 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
3819 gint64 base_offset, running_offset;
3822 /* NOTE @stream ignored */
3824 moof_node = g_node_new ((guint8 *) buffer);
3825 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
3826 qtdemux_node_dump (qtdemux, moof_node);
3828 /* Get fragment number from mfhd and check it's valid */
3830 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
3831 if (mfhd_node == NULL)
3833 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
3835 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
3837 /* unknown base_offset to start with */
3838 base_offset = running_offset = -1;
3839 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
3841 guint64 decode_time = 0;
3843 /* Fragment Header node */
3845 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
3849 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
3850 &ds_size, &ds_flags, &base_offset))
3853 /* The following code assumes at most a single set of sample auxiliary
3854 * data in the fragment (consisting of a saiz box and a corresponding saio
3855 * box); in theory, however, there could be multiple sets of sample
3856 * auxiliary data in a fragment. */
3858 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
3861 guint32 info_type = 0;
3863 guint32 info_type_parameter = 0;
3865 g_free (qtdemux->cenc_aux_info_sizes);
3867 qtdemux->cenc_aux_info_sizes =
3868 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
3869 &qtdemux->cenc_aux_sample_count);
3870 if (qtdemux->cenc_aux_info_sizes == NULL) {
3871 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
3875 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
3878 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
3879 g_free (qtdemux->cenc_aux_info_sizes);
3880 qtdemux->cenc_aux_info_sizes = NULL;
3884 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
3885 &info_type, &info_type_parameter, &offset))) {
3886 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
3887 g_free (qtdemux->cenc_aux_info_sizes);
3888 qtdemux->cenc_aux_info_sizes = NULL;
3891 if (base_offset > -1 && base_offset > qtdemux->moof_offset)
3892 offset += (guint64) (base_offset - qtdemux->moof_offset);
3893 if (info_type == FOURCC_cenc && info_type_parameter == 0U) {
3895 if (offset > length) {
3896 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
3897 qtdemux->cenc_aux_info_offset = offset;
3899 gst_byte_reader_init (&br, buffer + offset, length - offset);
3900 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
3901 qtdemux->cenc_aux_info_sizes,
3902 qtdemux->cenc_aux_sample_count)) {
3903 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
3904 g_free (qtdemux->cenc_aux_info_sizes);
3905 qtdemux->cenc_aux_info_sizes = NULL;
3913 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
3916 /* We'll use decode_time to interpolate timestamps
3917 * in case the input timestamps are missing */
3918 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
3920 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
3921 " (%" GST_TIME_FORMAT ")", decode_time,
3922 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_time)));
3924 /* Discard the fragment buffer timestamp info to avoid using it.
3925 * Rely on tfdt instead as it is more accurate than the timestamp
3926 * that is fetched from a manifest/playlist and is usually
3928 qtdemux->fragment_start = -1;
3931 if (G_UNLIKELY (!stream)) {
3932 /* we lost track of offset, we'll need to regain it,
3933 * but can delay complaining until later or avoid doing so altogether */
3937 if (G_UNLIKELY (base_offset < -1))
3940 if (qtdemux->upstream_format_is_time)
3941 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
3943 /* initialise moof sample data */
3944 stream->n_samples_moof = 0;
3945 stream->duration_last_moof = stream->duration_moof;
3946 stream->duration_moof = 0;
3948 /* Track Run node */
3950 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
3953 qtdemux_parse_trun (qtdemux, &trun_data, stream,
3954 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
3955 &running_offset, decode_time, (tfdt_node != NULL));
3956 /* iterate all siblings */
3957 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
3961 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
3963 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
3964 guint32 box_length = QT_UINT32 (uuid_buffer);
3966 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
3969 /* if no new base_offset provided for next traf,
3970 * base is end of current traf */
3971 base_offset = running_offset;
3972 running_offset = -1;
3974 if (stream->n_samples_moof && stream->duration_moof)
3975 stream->new_caps = TRUE;
3978 /* iterate all siblings */
3979 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
3982 /* parse any protection system info */
3983 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
3985 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
3986 qtdemux_parse_pssh (qtdemux, pssh_node);
3987 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
3990 g_node_destroy (moof_node);
3995 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
4000 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
4005 GST_DEBUG_OBJECT (qtdemux, "lost offset");
4010 g_node_destroy (moof_node);
4011 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4012 (_("This file is corrupt and cannot be played.")), (NULL));
4018 /* might be used if some day we actually use mfra & co
4019 * for random access to fragments,
4020 * but that will require quite some modifications and much less relying
4021 * on a sample array */
4025 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
4027 QtDemuxStream *stream;
4028 guint32 ver_flags, track_id, len, num_entries, i;
4029 guint value_size, traf_size, trun_size, sample_size;
4030 guint64 time = 0, moof_offset = 0;
4032 GstBuffer *buf = NULL;
4037 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
4039 if (!gst_byte_reader_skip (&tfra, 8))
4042 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
4045 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
4046 || !gst_byte_reader_get_uint32_be (&tfra, &len)
4047 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
4050 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
4052 stream = qtdemux_find_stream (qtdemux, track_id);
4054 goto unknown_trackid;
4056 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
4057 sample_size = (len & 3) + 1;
4058 trun_size = ((len & 12) >> 2) + 1;
4059 traf_size = ((len & 48) >> 4) + 1;
4061 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
4062 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
4064 if (num_entries == 0)
4067 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
4068 value_size + value_size + traf_size + trun_size + sample_size))
4071 g_free (stream->ra_entries);
4072 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
4073 stream->n_ra_entries = num_entries;
4075 for (i = 0; i < num_entries; i++) {
4076 qt_atom_parser_get_offset (&tfra, value_size, &time);
4077 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
4078 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
4079 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
4080 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
4082 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
4084 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
4085 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
4087 stream->ra_entries[i].ts = time;
4088 stream->ra_entries[i].moof_offset = moof_offset;
4090 /* don't want to go through the entire file and read all moofs at startup */
4092 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
4093 if (ret != GST_FLOW_OK)
4095 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
4096 moof_offset, stream);
4097 gst_buffer_unref (buf);
4101 check_update_duration (qtdemux, time);
4108 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
4113 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
4118 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4124 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
4126 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
4127 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
4128 GstBuffer *mfro = NULL, *mfra = NULL;
4130 gboolean ret = FALSE;
4131 GNode *mfra_node, *tfra_node;
4132 guint64 mfra_offset = 0;
4133 guint32 fourcc, mfra_size;
4136 /* query upstream size in bytes */
4137 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4138 goto size_query_failed;
4140 /* mfro box should be at the very end of the file */
4141 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4142 if (flow != GST_FLOW_OK)
4145 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4147 fourcc = QT_FOURCC (mfro_map.data + 4);
4148 if (fourcc != FOURCC_mfro)
4151 GST_INFO_OBJECT (qtdemux, "Found mfro box");
4152 if (mfro_map.size < 16)
4153 goto invalid_mfro_size;
4155 mfra_size = QT_UINT32 (mfro_map.data + 12);
4156 if (mfra_size >= len)
4157 goto invalid_mfra_size;
4159 mfra_offset = len - mfra_size;
4161 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4162 mfra_offset, mfra_size);
4164 /* now get and parse mfra box */
4165 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4166 if (flow != GST_FLOW_OK)
4169 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4171 mfra_node = g_node_new ((guint8 *) mfra_map.data);
4172 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4174 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4177 qtdemux_parse_tfra (qtdemux, tfra_node);
4178 /* iterate all siblings */
4179 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4181 g_node_destroy (mfra_node);
4183 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4189 if (mfro_map.memory != NULL)
4190 gst_buffer_unmap (mfro, &mfro_map);
4191 gst_buffer_unref (mfro);
4194 if (mfra_map.memory != NULL)
4195 gst_buffer_unmap (mfra, &mfra_map);
4196 gst_buffer_unref (mfra);
4203 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4208 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4213 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4218 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4224 add_offset (guint64 offset, guint64 advance)
4226 /* Avoid 64-bit overflow by clamping */
4227 if (offset > G_MAXUINT64 - advance)
4229 return offset + advance;
4232 static GstFlowReturn
4233 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4237 GstBuffer *buf = NULL;
4238 GstFlowReturn ret = GST_FLOW_OK;
4239 guint64 cur_offset = qtdemux->offset;
4242 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4243 if (G_UNLIKELY (ret != GST_FLOW_OK))
4245 gst_buffer_map (buf, &map, GST_MAP_READ);
4246 if (G_LIKELY (map.size >= 8))
4247 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4248 gst_buffer_unmap (buf, &map);
4249 gst_buffer_unref (buf);
4251 /* maybe we already got most we needed, so only consider this eof */
4252 if (G_UNLIKELY (length == 0)) {
4253 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4254 (_("Invalid atom size.")),
4255 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4256 GST_FOURCC_ARGS (fourcc)));
4263 /* record for later parsing when needed */
4264 if (!qtdemux->moof_offset) {
4265 qtdemux->moof_offset = qtdemux->offset;
4267 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4270 qtdemux->offset += length; /* skip moof and keep going */
4272 if (qtdemux->got_moov) {
4273 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4284 GST_LOG_OBJECT (qtdemux,
4285 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4286 GST_FOURCC_ARGS (fourcc), cur_offset);
4287 qtdemux->offset = add_offset (qtdemux->offset, length);
4292 GstBuffer *moov = NULL;
4294 if (qtdemux->got_moov) {
4295 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4296 qtdemux->offset = add_offset (qtdemux->offset, length);
4300 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4301 if (ret != GST_FLOW_OK)
4303 gst_buffer_map (moov, &map, GST_MAP_READ);
4305 if (length != map.size) {
4306 /* Some files have a 'moov' atom at the end of the file which contains
4307 * a terminal 'free' atom where the body of the atom is missing.
4308 * Check for, and permit, this special case.
4310 if (map.size >= 8) {
4311 guint8 *final_data = map.data + (map.size - 8);
4312 guint32 final_length = QT_UINT32 (final_data);
4313 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4315 if (final_fourcc == FOURCC_free
4316 && map.size + final_length - 8 == length) {
4317 /* Ok, we've found that special case. Allocate a new buffer with
4318 * that free atom actually present. */
4319 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4320 gst_buffer_fill (newmoov, 0, map.data, map.size);
4321 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4322 gst_buffer_unmap (moov, &map);
4323 gst_buffer_unref (moov);
4325 gst_buffer_map (moov, &map, GST_MAP_READ);
4330 if (length != map.size) {
4331 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4332 (_("This file is incomplete and cannot be played.")),
4333 ("We got less than expected (received %" G_GSIZE_FORMAT
4334 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4335 (guint) length, cur_offset));
4336 gst_buffer_unmap (moov, &map);
4337 gst_buffer_unref (moov);
4338 ret = GST_FLOW_ERROR;
4341 qtdemux->offset += length;
4343 qtdemux_parse_moov (qtdemux, map.data, length);
4344 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4346 qtdemux_parse_tree (qtdemux);
4347 if (qtdemux->moov_node_compressed) {
4348 g_node_destroy (qtdemux->moov_node_compressed);
4349 g_free (qtdemux->moov_node->data);
4351 qtdemux->moov_node_compressed = NULL;
4352 g_node_destroy (qtdemux->moov_node);
4353 qtdemux->moov_node = NULL;
4354 gst_buffer_unmap (moov, &map);
4355 gst_buffer_unref (moov);
4356 qtdemux->got_moov = TRUE;
4362 GstBuffer *ftyp = NULL;
4364 /* extract major brand; might come in handy for ISO vs QT issues */
4365 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4366 if (ret != GST_FLOW_OK)
4368 qtdemux->offset += length;
4369 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4370 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4371 gst_buffer_unmap (ftyp, &map);
4372 gst_buffer_unref (ftyp);
4377 GstBuffer *uuid = NULL;
4379 /* uuid are extension atoms */
4380 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4381 if (ret != GST_FLOW_OK)
4383 qtdemux->offset += length;
4384 gst_buffer_map (uuid, &map, GST_MAP_READ);
4385 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4386 gst_buffer_unmap (uuid, &map);
4387 gst_buffer_unref (uuid);
4392 GstBuffer *sidx = NULL;
4393 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4394 if (ret != GST_FLOW_OK)
4396 qtdemux->offset += length;
4397 gst_buffer_map (sidx, &map, GST_MAP_READ);
4398 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4399 gst_buffer_unmap (sidx, &map);
4400 gst_buffer_unref (sidx);
4405 GstBuffer *unknown = NULL;
4407 GST_LOG_OBJECT (qtdemux,
4408 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4409 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4411 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4412 if (ret != GST_FLOW_OK)
4414 gst_buffer_map (unknown, &map, GST_MAP_READ);
4415 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4416 gst_buffer_unmap (unknown, &map);
4417 gst_buffer_unref (unknown);
4418 qtdemux->offset += length;
4424 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4425 /* digested all data, show what we have */
4426 qtdemux_prepare_streams (qtdemux);
4427 ret = qtdemux_expose_streams (qtdemux);
4429 qtdemux->state = QTDEMUX_STATE_MOVIE;
4430 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4437 /* Seeks to the previous keyframe of the indexed stream and
4438 * aligns other streams with respect to the keyframe timestamp
4439 * of indexed stream. Only called in case of Reverse Playback
4441 static GstFlowReturn
4442 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4445 guint32 seg_idx = 0, k_index = 0;
4446 guint32 ref_seg_idx, ref_k_index;
4447 GstClockTime k_pos = 0, last_stop = 0;
4448 QtDemuxSegment *seg = NULL;
4449 QtDemuxStream *ref_str = NULL;
4450 guint64 seg_media_start_mov; /* segment media start time in mov format */
4453 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4454 * and finally align all the other streams on that timestamp with their
4455 * respective keyframes */
4456 for (n = 0; n < qtdemux->n_streams; n++) {
4457 QtDemuxStream *str = qtdemux->streams[n];
4459 /* No candidate yet, take the first stream */
4465 /* So that stream has a segment, we prefer video streams */
4466 if (str->subtype == FOURCC_vide) {
4472 if (G_UNLIKELY (!ref_str)) {
4473 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4477 if (G_UNLIKELY (!ref_str->from_sample)) {
4478 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4482 /* So that stream has been playing from from_sample to to_sample. We will
4483 * get the timestamp of the previous sample and search for a keyframe before
4484 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4485 if (ref_str->subtype == FOURCC_vide) {
4486 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4487 ref_str->from_sample - 1, FALSE);
4489 if (ref_str->from_sample >= 10)
4490 k_index = ref_str->from_sample - 10;
4496 ref_str->samples[k_index].timestamp +
4497 ref_str->samples[k_index].pts_offset;
4499 /* get current segment for that stream */
4500 seg = &ref_str->segments[ref_str->segment_index];
4501 /* Use segment start in original timescale for comparisons */
4502 seg_media_start_mov = seg->trak_media_start;
4504 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4505 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT "\n",
4506 k_index, target_ts, seg_media_start_mov,
4507 GST_TIME_ARGS (seg->media_start));
4509 /* Crawl back through segments to find the one containing this I frame */
4510 while (target_ts < seg_media_start_mov) {
4511 GST_DEBUG_OBJECT (qtdemux,
4512 "keyframe position (sample %u) is out of segment %u " " target %"
4513 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4514 ref_str->segment_index, target_ts, seg_media_start_mov);
4516 if (G_UNLIKELY (!ref_str->segment_index)) {
4517 /* Reached first segment, let's consider it's EOS */
4520 ref_str->segment_index--;
4521 seg = &ref_str->segments[ref_str->segment_index];
4522 /* Use segment start in original timescale for comparisons */
4523 seg_media_start_mov = seg->trak_media_start;
4525 /* Calculate time position of the keyframe and where we should stop */
4527 QTSTREAMTIME_TO_GSTTIME (ref_str,
4528 target_ts - seg->trak_media_start) + seg->time;
4530 QTSTREAMTIME_TO_GSTTIME (ref_str,
4531 ref_str->samples[ref_str->from_sample].timestamp -
4532 seg->trak_media_start) + seg->time;
4534 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4535 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4536 k_index, GST_TIME_ARGS (k_pos));
4538 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4539 qtdemux->segment.position = last_stop;
4540 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4541 GST_TIME_ARGS (last_stop));
4543 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4544 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4548 ref_seg_idx = ref_str->segment_index;
4549 ref_k_index = k_index;
4551 /* Align them all on this */
4552 for (n = 0; n < qtdemux->n_streams; n++) {
4554 GstClockTime seg_time = 0;
4555 QtDemuxStream *str = qtdemux->streams[n];
4557 /* aligning reference stream again might lead to backing up to yet another
4558 * keyframe (due to timestamp rounding issues),
4559 * potentially putting more load on downstream; so let's try to avoid */
4560 if (str == ref_str) {
4561 seg_idx = ref_seg_idx;
4562 seg = &str->segments[seg_idx];
4563 k_index = ref_k_index;
4564 GST_DEBUG_OBJECT (qtdemux, "reference stream %d segment %d, "
4565 "sample at index %d", n, ref_str->segment_index, k_index);
4567 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4568 GST_DEBUG_OBJECT (qtdemux,
4569 "stream %d align segment %d for keyframe pos %" GST_TIME_FORMAT, n,
4570 seg_idx, GST_TIME_ARGS (k_pos));
4572 /* get segment and time in the segment */
4573 seg = &str->segments[seg_idx];
4574 seg_time = k_pos - seg->time;
4576 /* get the media time in the segment.
4577 * No adjustment for empty "filler" segments */
4578 if (seg->media_start != GST_CLOCK_TIME_NONE)
4579 seg_time += seg->media_start;
4581 /* get the index of the sample with media time */
4582 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4583 GST_DEBUG_OBJECT (qtdemux,
4584 "stream %d sample for %" GST_TIME_FORMAT " at %u", n,
4585 GST_TIME_ARGS (seg_time), index);
4587 /* find previous keyframe */
4588 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
4591 /* Remember until where we want to go */
4592 str->to_sample = str->from_sample - 1;
4593 /* Define our time position */
4595 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4596 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4597 if (seg->media_start != GST_CLOCK_TIME_NONE)
4598 str->time_position -= seg->media_start;
4600 /* Now seek back in time */
4601 gst_qtdemux_move_stream (qtdemux, str, k_index);
4602 GST_DEBUG_OBJECT (qtdemux, "stream %d keyframe at %u, time position %"
4603 GST_TIME_FORMAT " playing from sample %u to %u", n, k_index,
4604 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4610 return GST_FLOW_EOS;
4614 * Gets the current qt segment start, stop and position for the
4615 * given time offset. This is used in update_segment()
4618 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
4619 QtDemuxStream * stream, GstClockTime offset,
4620 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
4622 GstClockTime seg_time;
4623 GstClockTime start, stop, time;
4624 QtDemuxSegment *segment;
4626 segment = &stream->segments[stream->segment_index];
4628 /* get time in this segment */
4629 seg_time = (offset - segment->time) * segment->rate;
4631 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4632 GST_TIME_ARGS (seg_time));
4634 if (G_UNLIKELY (seg_time > segment->duration)) {
4635 GST_LOG_OBJECT (stream->pad,
4636 "seg_time > segment->duration %" GST_TIME_FORMAT,
4637 GST_TIME_ARGS (segment->duration));
4638 seg_time = segment->duration;
4641 /* qtdemux->segment.stop is in outside-time-realm, whereas
4642 * segment->media_stop is in track-time-realm.
4644 * In order to compare the two, we need to bring segment.stop
4645 * into the track-time-realm
4647 * FIXME - does this comment still hold? Don't see any conversion here */
4649 stop = qtdemux->segment.stop;
4650 if (stop == GST_CLOCK_TIME_NONE)
4651 stop = qtdemux->segment.duration;
4652 if (stop == GST_CLOCK_TIME_NONE)
4653 stop = segment->media_stop;
4656 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4658 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4659 start = segment->time + seg_time;
4661 stop = start - seg_time + segment->duration;
4662 } else if (qtdemux->segment.rate >= 0) {
4663 start = MIN (segment->media_start + seg_time, stop);
4666 if (segment->media_start >= qtdemux->segment.start) {
4667 time = segment->time;
4669 time = segment->time + (qtdemux->segment.start - segment->media_start);
4672 start = MAX (segment->media_start, qtdemux->segment.start);
4673 stop = MIN (segment->media_start + seg_time, stop);
4682 * Updates the qt segment used for the stream and pushes a new segment event
4683 * downstream on this stream's pad.
4686 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4687 gint seg_idx, GstClockTime offset, GstClockTime * _start,
4688 GstClockTime * _stop)
4690 QtDemuxSegment *segment;
4691 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
4695 /* update the current segment */
4696 stream->segment_index = seg_idx;
4698 /* get the segment */
4699 segment = &stream->segments[seg_idx];
4701 if (G_UNLIKELY (offset < segment->time)) {
4702 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4703 GST_TIME_ARGS (segment->time));
4707 /* segment lies beyond total indicated duration */
4708 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4709 segment->time > qtdemux->segment.duration)) {
4710 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4711 " < segment->time %" GST_TIME_FORMAT,
4712 GST_TIME_ARGS (qtdemux->segment.duration),
4713 GST_TIME_ARGS (segment->time));
4717 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
4718 &start, &stop, &time);
4720 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
4721 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
4722 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
4724 /* combine global rate with that of the segment */
4725 rate = segment->rate * qtdemux->segment.rate;
4727 /* Copy flags from main segment */
4728 stream->segment.flags = qtdemux->segment.flags;
4730 /* update the segment values used for clipping */
4731 stream->segment.offset = qtdemux->segment.offset;
4732 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
4733 stream->segment.applied_rate = qtdemux->segment.applied_rate;
4734 stream->segment.rate = rate;
4735 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
4736 stream->cslg_shift);
4737 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
4738 stream->cslg_shift);
4739 stream->segment.time = time;
4740 stream->segment.position = stream->segment.start;
4742 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
4745 /* now prepare and send the segment */
4747 event = gst_event_new_segment (&stream->segment);
4748 if (qtdemux->segment_seqnum) {
4749 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
4751 gst_pad_push_event (stream->pad, event);
4752 /* assume we can send more data now */
4753 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
4754 /* clear to send tags on this pad now */
4755 gst_qtdemux_push_tags (qtdemux, stream);
4766 /* activate the given segment number @seg_idx of @stream at time @offset.
4767 * @offset is an absolute global position over all the segments.
4769 * This will push out a NEWSEGMENT event with the right values and
4770 * position the stream index to the first decodable sample before
4774 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4775 guint32 seg_idx, GstClockTime offset)
4777 QtDemuxSegment *segment;
4778 guint32 index, kf_index;
4779 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
4781 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
4782 seg_idx, GST_TIME_ARGS (offset));
4784 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
4788 segment = &stream->segments[stream->segment_index];
4790 /* in the fragmented case, we pick a fragment that starts before our
4791 * desired position and rely on downstream to wait for a keyframe
4792 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
4793 * tfra entries tells us which trun/sample the key unit is in, but we don't
4794 * make use of this additional information at the moment) */
4795 if (qtdemux->fragmented) {
4796 stream->to_sample = G_MAXUINT32;
4800 /* We don't need to look for a sample in push-based */
4801 if (!qtdemux->pullbased)
4804 /* and move to the keyframe before the indicated media time of the
4806 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
4807 if (qtdemux->segment.rate >= 0) {
4808 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
4809 stream->to_sample = G_MAXUINT32;
4810 GST_DEBUG_OBJECT (stream->pad,
4811 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4812 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
4813 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4815 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
4816 stream->to_sample = index;
4817 GST_DEBUG_OBJECT (stream->pad,
4818 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4819 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
4820 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4823 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
4824 "this is an empty segment");
4828 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
4829 * encountered an error and printed a message so we return appropriately */
4833 /* we're at the right spot */
4834 if (index == stream->sample_index) {
4835 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
4839 /* find keyframe of the target index */
4840 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
4843 /* indent does stupid stuff with stream->samples[].timestamp */
4845 /* if we move forwards, we don't have to go back to the previous
4846 * keyframe since we already sent that. We can also just jump to
4847 * the keyframe right before the target index if there is one. */
4848 if (index > stream->sample_index) {
4849 /* moving forwards check if we move past a keyframe */
4850 if (kf_index > stream->sample_index) {
4851 GST_DEBUG_OBJECT (stream->pad,
4852 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4853 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4854 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4855 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4857 GST_DEBUG_OBJECT (stream->pad,
4858 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
4859 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
4860 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
4863 GST_DEBUG_OBJECT (stream->pad,
4864 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4865 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4866 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4867 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4875 /* prepare to get the current sample of @stream, getting essential values.
4877 * This function will also prepare and send the segment when needed.
4879 * Return FALSE if the stream is EOS.
4884 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
4885 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
4886 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
4887 gboolean * keyframe)
4889 QtDemuxSample *sample;
4890 GstClockTime time_position;
4893 g_return_val_if_fail (stream != NULL, FALSE);
4895 time_position = stream->time_position;
4896 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
4899 seg_idx = stream->segment_index;
4900 if (G_UNLIKELY (seg_idx == -1)) {
4901 /* find segment corresponding to time_position if we are looking
4903 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
4906 /* different segment, activate it, sample_index will be set. */
4907 if (G_UNLIKELY (stream->segment_index != seg_idx))
4908 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
4910 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->segments[stream->
4912 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
4914 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
4915 " prepare empty sample");
4918 *pts = *dts = time_position;
4919 *duration = seg->duration - (time_position - seg->time);
4926 if (stream->sample_index == -1)
4927 stream->sample_index = 0;
4929 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
4930 stream->sample_index, stream->n_samples);
4932 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
4933 if (!qtdemux->fragmented)
4936 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
4940 GST_OBJECT_LOCK (qtdemux);
4941 flow = qtdemux_add_fragmented_samples (qtdemux);
4942 GST_OBJECT_UNLOCK (qtdemux);
4944 if (flow != GST_FLOW_OK)
4947 while (stream->sample_index >= stream->n_samples);
4950 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4951 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4952 stream->sample_index);
4956 /* now get the info for the sample we're at */
4957 sample = &stream->samples[stream->sample_index];
4959 *dts = QTSAMPLE_DTS (stream, sample);
4960 *pts = QTSAMPLE_PTS (stream, sample);
4961 *offset = sample->offset;
4962 *size = sample->size;
4963 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
4964 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
4971 stream->time_position = GST_CLOCK_TIME_NONE;
4976 /* move to the next sample in @stream.
4978 * Moves to the next segment when needed.
4981 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
4983 QtDemuxSample *sample;
4984 QtDemuxSegment *segment;
4986 /* get current segment */
4987 segment = &stream->segments[stream->segment_index];
4989 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4990 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
4994 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
4995 /* Mark the stream as EOS */
4996 GST_DEBUG_OBJECT (qtdemux,
4997 "reached max allowed sample %u, mark EOS", stream->to_sample);
4998 stream->time_position = GST_CLOCK_TIME_NONE;
5002 /* move to next sample */
5003 stream->sample_index++;
5004 stream->offset_in_sample = 0;
5006 /* reached the last sample, we need the next segment */
5007 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
5010 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5011 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5012 stream->sample_index);
5016 /* get next sample */
5017 sample = &stream->samples[stream->sample_index];
5019 /* see if we are past the segment */
5020 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
5023 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
5024 /* inside the segment, update time_position, looks very familiar to
5025 * GStreamer segments, doesn't it? */
5026 stream->time_position =
5027 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
5029 /* not yet in segment, time does not yet increment. This means
5030 * that we are still prerolling keyframes to the decoder so it can
5031 * decode the first sample of the segment. */
5032 stream->time_position = segment->time;
5036 /* move to the next segment */
5039 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
5041 if (stream->segment_index == stream->n_segments - 1) {
5042 /* are we at the end of the last segment, we're EOS */
5043 stream->time_position = GST_CLOCK_TIME_NONE;
5045 /* else we're only at the end of the current segment */
5046 stream->time_position = segment->stop_time;
5048 /* make sure we select a new segment */
5050 /* accumulate previous segments */
5051 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
5052 stream->accumulated_base +=
5053 (stream->segment.stop -
5054 stream->segment.start) / ABS (stream->segment.rate);
5056 stream->segment_index = -1;
5061 gst_qtdemux_sync_streams (GstQTDemux * demux)
5065 if (demux->n_streams <= 1)
5068 for (i = 0; i < demux->n_streams; i++) {
5069 QtDemuxStream *stream;
5070 GstClockTime end_time;
5072 stream = demux->streams[i];
5077 /* TODO advance time on subtitle streams here, if any some day */
5079 /* some clips/trailers may have unbalanced streams at the end,
5080 * so send EOS on shorter stream to prevent stalling others */
5082 /* do not mess with EOS if SEGMENT seeking */
5083 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5086 if (demux->pullbased) {
5087 /* loop mode is sample time based */
5088 if (!STREAM_IS_EOS (stream))
5091 /* push mode is byte position based */
5092 if (stream->n_samples &&
5093 stream->samples[stream->n_samples - 1].offset >= demux->offset)
5097 if (stream->sent_eos)
5100 /* only act if some gap */
5101 end_time = stream->segments[stream->n_segments - 1].stop_time;
5102 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5103 ", stream end: %" GST_TIME_FORMAT,
5104 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5105 if (GST_CLOCK_TIME_IS_VALID (end_time)
5106 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5109 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5110 GST_PAD_NAME (stream->pad));
5111 stream->sent_eos = TRUE;
5112 event = gst_event_new_eos ();
5113 if (demux->segment_seqnum)
5114 gst_event_set_seqnum (event, demux->segment_seqnum);
5115 gst_pad_push_event (stream->pad, event);
5120 /* EOS and NOT_LINKED need to be combined. This means that we return:
5122 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
5123 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
5125 static GstFlowReturn
5126 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
5129 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
5132 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5135 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5137 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5141 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5142 * completely clipped
5144 * Should be used only with raw buffers */
5146 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5149 guint64 start, stop, cstart, cstop, diff;
5150 GstClockTime pts, duration;
5152 gint num_rate, denom_rate;
5157 osize = size = gst_buffer_get_size (buf);
5160 /* depending on the type, setup the clip parameters */
5161 if (stream->subtype == FOURCC_soun) {
5162 frame_size = CUR_STREAM (stream)->bytes_per_frame;
5163 num_rate = GST_SECOND;
5164 denom_rate = (gint) CUR_STREAM (stream)->rate;
5166 } else if (stream->subtype == FOURCC_vide) {
5168 num_rate = CUR_STREAM (stream)->fps_n;
5169 denom_rate = CUR_STREAM (stream)->fps_d;
5174 if (frame_size <= 0)
5175 goto bad_frame_size;
5177 /* we can only clip if we have a valid pts */
5178 pts = GST_BUFFER_PTS (buf);
5179 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5182 duration = GST_BUFFER_DURATION (buf);
5184 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5186 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5190 stop = start + duration;
5192 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5193 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5196 /* see if some clipping happened */
5197 diff = cstart - start;
5203 /* bring clipped time to samples and to bytes */
5204 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5207 GST_DEBUG_OBJECT (qtdemux,
5208 "clipping start to %" GST_TIME_FORMAT " %"
5209 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5215 diff = stop - cstop;
5220 /* bring clipped time to samples and then to bytes */
5221 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5223 GST_DEBUG_OBJECT (qtdemux,
5224 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5225 " bytes", GST_TIME_ARGS (cstop), diff);
5230 if (offset != 0 || size != osize)
5231 gst_buffer_resize (buf, offset, size);
5233 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5234 GST_BUFFER_PTS (buf) = pts;
5235 GST_BUFFER_DURATION (buf) = duration;
5239 /* dropped buffer */
5242 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5247 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5252 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5257 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5258 gst_buffer_unref (buf);
5264 gst_qtdemux_align_buffer (GstQTDemux * demux,
5265 GstBuffer * buffer, gsize alignment)
5269 gst_buffer_map (buffer, &map, GST_MAP_READ);
5271 if (map.size < sizeof (guintptr)) {
5272 gst_buffer_unmap (buffer, &map);
5276 if (((guintptr) map.data) & (alignment - 1)) {
5277 GstBuffer *new_buffer;
5278 GstAllocationParams params = { 0, alignment - 1, 0, 0, };
5280 new_buffer = gst_buffer_new_allocate (NULL,
5281 gst_buffer_get_size (buffer), ¶ms);
5283 /* Copy data "by hand", so ensure alignment is kept: */
5284 gst_buffer_fill (new_buffer, 0, map.data, map.size);
5286 gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
5287 GST_DEBUG_OBJECT (demux,
5288 "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
5291 gst_buffer_unmap (buffer, &map);
5292 gst_buffer_unref (buffer);
5297 gst_buffer_unmap (buffer, &map);
5301 /* the input buffer metadata must be writable,
5302 * but time/duration etc not yet set and need not be preserved */
5304 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5311 /* not many cases for now */
5312 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_mp4s)) {
5313 /* send a one time dvd clut event */
5314 if (stream->pending_event && stream->pad)
5315 gst_pad_push_event (stream->pad, stream->pending_event);
5316 stream->pending_event = NULL;
5319 if (G_UNLIKELY (stream->subtype != FOURCC_text
5320 && stream->subtype != FOURCC_sbtl &&
5321 stream->subtype != FOURCC_subp)) {
5325 gst_buffer_map (buf, &map, GST_MAP_READ);
5327 /* empty buffer is sent to terminate previous subtitle */
5328 if (map.size <= 2) {
5329 gst_buffer_unmap (buf, &map);
5330 gst_buffer_unref (buf);
5333 if (stream->subtype == FOURCC_subp) {
5334 /* That's all the processing needed for subpictures */
5335 gst_buffer_unmap (buf, &map);
5339 nsize = GST_READ_UINT16_BE (map.data);
5340 nsize = MIN (nsize, map.size - 2);
5342 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5345 /* takes care of UTF-8 validation or UTF-16 recognition,
5346 * no other encoding expected */
5347 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5348 gst_buffer_unmap (buf, &map);
5350 gst_buffer_unref (buf);
5351 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5353 /* this should not really happen unless the subtitle is corrupted */
5354 gst_buffer_unref (buf);
5358 /* FIXME ? convert optional subsequent style info to markup */
5363 /* Sets a buffer's attributes properly and pushes it downstream.
5364 * Also checks for additional actions and custom processing that may
5365 * need to be done first.
5367 static GstFlowReturn
5368 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
5369 QtDemuxStream * stream, GstBuffer * buf,
5370 GstClockTime dts, GstClockTime pts, GstClockTime duration,
5371 gboolean keyframe, GstClockTime position, guint64 byte_position)
5373 GstFlowReturn ret = GST_FLOW_OK;
5375 /* offset the timestamps according to the edit list */
5377 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) {
5381 gst_buffer_map (buf, &map, GST_MAP_READ);
5382 url = g_strndup ((gchar *) map.data, map.size);
5383 gst_buffer_unmap (buf, &map);
5384 if (url != NULL && strlen (url) != 0) {
5385 /* we have RTSP redirect now */
5386 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5387 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
5388 gst_structure_new ("redirect",
5389 "new-location", G_TYPE_STRING, url, NULL)));
5390 qtdemux->posted_redirect = TRUE;
5392 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
5398 /* position reporting */
5399 if (qtdemux->segment.rate >= 0) {
5400 qtdemux->segment.position = position;
5401 gst_qtdemux_sync_streams (qtdemux);
5404 if (G_UNLIKELY (!stream->pad)) {
5405 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
5406 gst_buffer_unref (buf);
5410 /* send out pending buffers */
5411 while (stream->buffers) {
5412 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
5414 if (G_UNLIKELY (stream->discont)) {
5415 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5416 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
5417 stream->discont = FALSE;
5419 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5422 if (stream->alignment > 1)
5423 buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
5424 gst_pad_push (stream->pad, buffer);
5426 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
5429 /* we're going to modify the metadata */
5430 buf = gst_buffer_make_writable (buf);
5432 if (G_UNLIKELY (stream->need_process))
5433 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
5439 GST_BUFFER_DTS (buf) = dts;
5440 GST_BUFFER_PTS (buf) = pts;
5441 GST_BUFFER_DURATION (buf) = duration;
5442 GST_BUFFER_OFFSET (buf) = -1;
5443 GST_BUFFER_OFFSET_END (buf) = -1;
5445 if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette))
5446 gst_buffer_append_memory (buf,
5447 gst_memory_ref (CUR_STREAM (stream)->rgb8_palette));
5449 if (G_UNLIKELY (CUR_STREAM (stream)->padding)) {
5450 gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1);
5453 if (G_UNLIKELY (qtdemux->element_index)) {
5454 GstClockTime stream_time;
5457 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
5459 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
5460 GST_LOG_OBJECT (qtdemux,
5461 "adding association %" GST_TIME_FORMAT "-> %"
5462 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
5463 gst_index_add_association (qtdemux->element_index,
5465 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
5466 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
5467 GST_FORMAT_BYTES, byte_position, NULL);
5472 if (stream->need_clip)
5473 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5475 if (G_UNLIKELY (buf == NULL))
5478 if (G_UNLIKELY (stream->discont)) {
5479 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5480 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5481 stream->discont = FALSE;
5483 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5487 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
5488 stream->on_keyframe = FALSE;
5490 stream->on_keyframe = TRUE;
5494 GST_LOG_OBJECT (qtdemux,
5495 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5496 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
5497 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
5498 GST_PAD_NAME (stream->pad));
5500 if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) {
5501 GstStructure *crypto_info;
5502 QtDemuxCencSampleSetInfo *info =
5503 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5507 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5508 gst_pad_push_event (stream->pad, event);
5511 if (info->crypto_info == NULL) {
5512 GST_DEBUG_OBJECT (qtdemux, "cenc metadata hasn't been parsed yet");
5513 gst_buffer_unref (buf);
5517 /* The end of the crypto_info array matches our n_samples position,
5518 * so count backward from there */
5519 index = stream->sample_index - stream->n_samples + info->crypto_info->len;
5520 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5521 /* steal structure from array */
5522 crypto_info = g_ptr_array_index (info->crypto_info, index);
5523 g_ptr_array_index (info->crypto_info, index) = NULL;
5524 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
5525 info->crypto_info->len);
5526 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5527 GST_ERROR_OBJECT (qtdemux, "failed to attach cenc metadata to buffer");
5529 GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
5530 index, stream->sample_index);
5534 if (stream->alignment > 1)
5535 buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
5537 ret = gst_pad_push (stream->pad, buf);
5539 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
5540 /* mark position in stream, we'll need this to know when to send GAP event */
5541 stream->segment.position = pts + duration;
5548 static const QtDemuxRandomAccessEntry *
5549 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5550 GstClockTime pos, gboolean after)
5552 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
5553 guint n_entries = stream->n_ra_entries;
5556 /* we assume the table is sorted */
5557 for (i = 0; i < n_entries; ++i) {
5558 if (entries[i].ts > pos)
5562 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
5563 * probably okay to assume that the index lists the very first fragment */
5570 return &entries[i - 1];
5574 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
5576 const QtDemuxRandomAccessEntry *best_entry = NULL;
5579 GST_OBJECT_LOCK (qtdemux);
5581 g_assert (qtdemux->n_streams > 0);
5583 for (i = 0; i < qtdemux->n_streams; i++) {
5584 const QtDemuxRandomAccessEntry *entry;
5585 QtDemuxStream *stream;
5586 gboolean is_audio_or_video;
5588 stream = qtdemux->streams[i];
5590 g_free (stream->samples);
5591 stream->samples = NULL;
5592 stream->n_samples = 0;
5593 stream->stbl_index = -1; /* no samples have yet been parsed */
5594 stream->sample_index = -1;
5596 if (stream->protection_scheme_info) {
5597 /* Clear out any old cenc crypto info entries as we'll move to a new moof */
5598 if (stream->protection_scheme_type == FOURCC_cenc) {
5599 QtDemuxCencSampleSetInfo *info =
5600 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5601 if (info->crypto_info) {
5602 g_ptr_array_free (info->crypto_info, TRUE);
5603 info->crypto_info = NULL;
5608 if (stream->ra_entries == NULL)
5611 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
5612 is_audio_or_video = TRUE;
5614 is_audio_or_video = FALSE;
5617 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
5618 stream->time_position, !is_audio_or_video);
5620 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
5621 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
5623 stream->pending_seek = entry;
5625 /* decide position to jump to just based on audio/video tracks, not subs */
5626 if (!is_audio_or_video)
5629 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
5633 if (best_entry == NULL) {
5634 GST_OBJECT_UNLOCK (qtdemux);
5638 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
5639 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
5640 GST_TIME_ARGS (qtdemux->streams[0]->time_position),
5641 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
5643 qtdemux->moof_offset = best_entry->moof_offset;
5645 qtdemux_add_fragmented_samples (qtdemux);
5647 GST_OBJECT_UNLOCK (qtdemux);
5651 static GstFlowReturn
5652 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
5654 GstFlowReturn ret = GST_FLOW_OK;
5655 GstBuffer *buf = NULL;
5656 QtDemuxStream *stream;
5657 GstClockTime min_time;
5659 GstClockTime dts = GST_CLOCK_TIME_NONE;
5660 GstClockTime pts = GST_CLOCK_TIME_NONE;
5661 GstClockTime duration = 0;
5662 gboolean keyframe = FALSE;
5663 guint sample_size = 0;
5669 gst_qtdemux_push_pending_newsegment (qtdemux);
5671 if (qtdemux->fragmented_seek_pending) {
5672 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
5673 gst_qtdemux_do_fragmented_seek (qtdemux);
5674 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
5675 qtdemux->fragmented_seek_pending = FALSE;
5678 /* Figure out the next stream sample to output, min_time is expressed in
5679 * global time and runs over the edit list segments. */
5680 min_time = G_MAXUINT64;
5682 for (i = 0; i < qtdemux->n_streams; i++) {
5683 GstClockTime position;
5685 stream = qtdemux->streams[i];
5686 position = stream->time_position;
5688 /* position of -1 is EOS */
5689 if (position != GST_CLOCK_TIME_NONE && position < min_time) {
5690 min_time = position;
5695 if (G_UNLIKELY (index == -1)) {
5696 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
5700 /* check for segment end */
5701 if (G_UNLIKELY (qtdemux->segment.stop != -1
5702 && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
5703 || (qtdemux->segment.rate < 0
5704 && qtdemux->segment.start > min_time))
5705 && qtdemux->streams[index]->on_keyframe)) {
5706 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
5707 qtdemux->streams[index]->time_position = GST_CLOCK_TIME_NONE;
5711 /* gap events for subtitle streams */
5712 for (i = 0; i < qtdemux->n_streams; i++) {
5713 stream = qtdemux->streams[i];
5714 if (stream->pad && (stream->subtype == FOURCC_subp
5715 || stream->subtype == FOURCC_text
5716 || stream->subtype == FOURCC_sbtl)) {
5717 /* send one second gap events until the stream catches up */
5718 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
5719 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
5720 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
5721 stream->segment.position + GST_SECOND < min_time) {
5723 gst_event_new_gap (stream->segment.position, GST_SECOND);
5724 gst_pad_push_event (stream->pad, gap);
5725 stream->segment.position += GST_SECOND;
5730 stream = qtdemux->streams[index];
5731 /* fetch info for the current sample of this stream */
5732 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
5733 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
5736 gst_qtdemux_stream_check_and_change_stsd_index (qtdemux, stream);
5737 if (stream->new_caps) {
5738 gst_qtdemux_configure_stream (qtdemux, stream);
5739 qtdemux_do_allocation (qtdemux, stream);
5742 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
5743 if (G_UNLIKELY (qtdemux->
5744 segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
5745 if (stream->subtype == FOURCC_vide && !keyframe) {
5746 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on stream %d", index);
5751 GST_DEBUG_OBJECT (qtdemux,
5752 "pushing from stream %d, empty %d offset %" G_GUINT64_FORMAT
5753 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
5754 ", duration %" GST_TIME_FORMAT, index, empty, offset, sample_size,
5755 GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
5757 if (G_UNLIKELY (empty)) {
5758 /* empty segment, push a gap and move to the next one */
5759 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
5760 stream->segment.position = pts + duration;
5764 /* hmm, empty sample, skip and move to next sample */
5765 if (G_UNLIKELY (sample_size <= 0))
5768 /* last pushed sample was out of boundary, goto next sample */
5769 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
5772 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
5775 GST_DEBUG_OBJECT (qtdemux,
5776 "size %d larger than stream max_buffer_size %d, trimming",
5777 sample_size, stream->max_buffer_size);
5779 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
5782 if (qtdemux->cenc_aux_info_offset > 0) {
5785 GstBuffer *aux_info = NULL;
5787 /* pull the data stored before the sample */
5789 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
5790 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
5791 if (G_UNLIKELY (ret != GST_FLOW_OK))
5793 gst_buffer_map (aux_info, &map, GST_MAP_READ);
5794 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
5795 gst_byte_reader_init (&br, map.data + 8, map.size);
5796 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
5797 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
5798 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
5799 gst_buffer_unmap (aux_info, &map);
5800 gst_buffer_unref (aux_info);
5801 ret = GST_FLOW_ERROR;
5804 gst_buffer_unmap (aux_info, &map);
5805 gst_buffer_unref (aux_info);
5808 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
5811 if (stream->use_allocator) {
5812 /* if we have a per-stream allocator, use it */
5813 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
5816 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
5818 if (G_UNLIKELY (ret != GST_FLOW_OK))
5821 if (size != sample_size) {
5822 pts += gst_util_uint64_scale_int (GST_SECOND,
5823 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
5826 gst_util_uint64_scale_int (GST_SECOND,
5827 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
5830 gst_util_uint64_scale_int (GST_SECOND,
5831 size / CUR_STREAM (stream)->bytes_per_frame, stream->timescale);
5834 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
5835 dts, pts, duration, keyframe, min_time, offset);
5837 if (size != sample_size) {
5838 QtDemuxSample *sample = &stream->samples[stream->sample_index];
5839 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
5841 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
5843 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame);
5844 if (time_position >= segment->media_start) {
5845 /* inside the segment, update time_position, looks very familiar to
5846 * GStreamer segments, doesn't it? */
5847 stream->time_position = (time_position - segment->media_start) +
5850 /* not yet in segment, time does not yet increment. This means
5851 * that we are still prerolling keyframes to the decoder so it can
5852 * decode the first sample of the segment. */
5853 stream->time_position = segment->time;
5858 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
5859 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
5860 * we have no more data for the pad to push */
5861 if (ret == GST_FLOW_EOS)
5864 stream->offset_in_sample += size;
5865 if (stream->offset_in_sample >= sample_size) {
5866 gst_qtdemux_advance_sample (qtdemux, stream);
5871 gst_qtdemux_advance_sample (qtdemux, stream);
5879 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
5885 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
5886 /* EOS will be raised if all are EOS */
5893 gst_qtdemux_loop (GstPad * pad)
5895 GstQTDemux *qtdemux;
5899 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
5901 cur_offset = qtdemux->offset;
5902 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
5903 cur_offset, qt_demux_state_string (qtdemux->state));
5905 switch (qtdemux->state) {
5906 case QTDEMUX_STATE_INITIAL:
5907 case QTDEMUX_STATE_HEADER:
5908 ret = gst_qtdemux_loop_state_header (qtdemux);
5910 case QTDEMUX_STATE_MOVIE:
5911 ret = gst_qtdemux_loop_state_movie (qtdemux);
5912 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
5913 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
5921 /* if something went wrong, pause */
5922 if (ret != GST_FLOW_OK)
5926 gst_object_unref (qtdemux);
5932 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
5933 (NULL), ("streaming stopped, invalid state"));
5934 gst_pad_pause_task (pad);
5935 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5940 const gchar *reason = gst_flow_get_name (ret);
5942 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
5944 gst_pad_pause_task (pad);
5946 /* fatal errors need special actions */
5948 if (ret == GST_FLOW_EOS) {
5949 if (qtdemux->n_streams == 0) {
5950 /* we have no streams, post an error */
5951 gst_qtdemux_post_no_playable_stream_error (qtdemux);
5953 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
5956 if ((stop = qtdemux->segment.stop) == -1)
5957 stop = qtdemux->segment.duration;
5959 if (qtdemux->segment.rate >= 0) {
5960 GstMessage *message;
5963 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
5964 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5965 GST_FORMAT_TIME, stop);
5966 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
5967 if (qtdemux->segment_seqnum) {
5968 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
5969 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5971 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
5972 gst_qtdemux_push_event (qtdemux, event);
5974 GstMessage *message;
5977 /* For Reverse Playback */
5978 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
5979 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5980 GST_FORMAT_TIME, qtdemux->segment.start);
5981 event = gst_event_new_segment_done (GST_FORMAT_TIME,
5982 qtdemux->segment.start);
5983 if (qtdemux->segment_seqnum) {
5984 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
5985 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5987 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
5988 gst_qtdemux_push_event (qtdemux, event);
5993 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
5994 event = gst_event_new_eos ();
5995 if (qtdemux->segment_seqnum)
5996 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5997 gst_qtdemux_push_event (qtdemux, event);
5999 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
6000 GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
6001 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6010 * Returns if there are samples to be played.
6013 has_next_entry (GstQTDemux * demux)
6015 QtDemuxStream *stream;
6018 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
6020 for (i = 0; i < demux->n_streams; i++) {
6021 stream = demux->streams[i];
6023 if (stream->sample_index == -1) {
6024 stream->sample_index = 0;
6025 stream->offset_in_sample = 0;
6028 if (stream->sample_index >= stream->n_samples) {
6029 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
6032 GST_DEBUG_OBJECT (demux, "Found a sample");
6036 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
6043 * Returns the size of the first entry at the current offset.
6044 * If -1, there are none (which means EOS or empty file).
6047 next_entry_size (GstQTDemux * demux)
6049 QtDemuxStream *stream;
6052 guint64 smalloffs = (guint64) - 1;
6053 QtDemuxSample *sample;
6055 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
6058 for (i = 0; i < demux->n_streams; i++) {
6059 stream = demux->streams[i];
6061 if (stream->sample_index == -1) {
6062 stream->sample_index = 0;
6063 stream->offset_in_sample = 0;
6066 if (stream->sample_index >= stream->n_samples) {
6067 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
6071 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
6072 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
6073 stream->sample_index);
6077 sample = &stream->samples[stream->sample_index];
6079 GST_LOG_OBJECT (demux,
6080 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
6081 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
6082 sample->offset, sample->size);
6084 if (((smalloffs == -1)
6085 || (sample->offset < smalloffs)) && (sample->size)) {
6087 smalloffs = sample->offset;
6091 GST_LOG_OBJECT (demux,
6092 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
6093 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
6098 stream = demux->streams[smallidx];
6099 sample = &stream->samples[stream->sample_index];
6101 if (sample->offset >= demux->offset) {
6102 demux->todrop = sample->offset - demux->offset;
6103 return sample->size + demux->todrop;
6106 GST_DEBUG_OBJECT (demux,
6107 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
6112 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
6114 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
6116 gst_element_post_message (GST_ELEMENT_CAST (demux),
6117 gst_message_new_element (GST_OBJECT_CAST (demux),
6118 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
6122 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
6127 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
6130 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
6131 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
6132 GST_SEEK_TYPE_NONE, -1);
6134 /* store seqnum to drop flush events, they don't need to reach downstream */
6135 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
6136 res = gst_pad_push_event (demux->sinkpad, event);
6137 demux->offset_seek_seqnum = 0;
6142 /* check for seekable upstream, above and beyond a mere query */
6144 gst_qtdemux_check_seekability (GstQTDemux * demux)
6147 gboolean seekable = FALSE;
6148 gint64 start = -1, stop = -1;
6150 if (demux->upstream_size)
6153 if (demux->upstream_format_is_time)
6156 query = gst_query_new_seeking (GST_FORMAT_BYTES);
6157 if (!gst_pad_peer_query (demux->sinkpad, query)) {
6158 GST_DEBUG_OBJECT (demux, "seeking query failed");
6162 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
6164 /* try harder to query upstream size if we didn't get it the first time */
6165 if (seekable && stop == -1) {
6166 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
6167 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
6170 /* if upstream doesn't know the size, it's likely that it's not seekable in
6171 * practice even if it technically may be seekable */
6172 if (seekable && (start != 0 || stop <= start)) {
6173 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
6178 gst_query_unref (query);
6180 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
6181 G_GUINT64_FORMAT ")", seekable, start, stop);
6182 demux->upstream_seekable = seekable;
6183 demux->upstream_size = seekable ? stop : -1;
6187 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
6189 g_return_if_fail (bytes <= demux->todrop);
6191 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
6192 gst_adapter_flush (demux->adapter, bytes);
6193 demux->neededbytes -= bytes;
6194 demux->offset += bytes;
6195 demux->todrop -= bytes;
6199 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
6201 if (G_UNLIKELY (demux->pending_newsegment)) {
6204 gst_qtdemux_push_pending_newsegment (demux);
6205 /* clear to send tags on all streams */
6206 for (i = 0; i < demux->n_streams; i++) {
6207 QtDemuxStream *stream;
6208 stream = demux->streams[i];
6209 gst_qtdemux_push_tags (demux, stream);
6210 if (CUR_STREAM (stream)->sparse) {
6211 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
6212 gst_pad_push_event (stream->pad,
6213 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
6220 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
6221 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
6223 GstClockTime ts, dur;
6228 stream->segments[segment_index].duration - (pos -
6229 stream->segments[segment_index].time);
6230 gap = gst_event_new_gap (ts, dur);
6231 stream->time_position += dur;
6233 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
6234 "segment: %" GST_PTR_FORMAT, gap);
6235 gst_pad_push_event (stream->pad, gap);
6239 gst_qtdemux_stream_send_initial_gap_segments (GstQTDemux * demux,
6240 QtDemuxStream * stream)
6244 /* Push any initial gap segments before proceeding to the
6246 for (i = 0; i < stream->n_segments; i++) {
6247 gst_qtdemux_activate_segment (demux, stream, i, stream->time_position);
6249 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
6250 gst_qtdemux_send_gap_for_segment (demux, stream, i,
6251 stream->time_position);
6253 /* Only support empty segment at the beginning followed by
6254 * one non-empty segment, this was checked when parsing the
6255 * edts atom, arriving here is unexpected */
6256 g_assert (i + 1 == stream->n_segments);
6262 static GstFlowReturn
6263 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
6267 demux = GST_QTDEMUX (parent);
6269 GST_DEBUG_OBJECT (demux,
6270 "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
6271 " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
6272 G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
6273 GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
6274 gst_buffer_get_size (inbuf), demux->offset);
6276 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
6277 gboolean is_gap_input = FALSE;
6280 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
6282 for (i = 0; i < demux->n_streams; i++) {
6283 demux->streams[i]->discont = TRUE;
6286 /* Check if we can land back on our feet in the case where upstream is
6287 * handling the seeking/pushing of samples with gaps in between (like
6288 * in the case of trick-mode DASH for example) */
6289 if (demux->upstream_format_is_time
6290 && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
6292 for (i = 0; i < demux->n_streams; i++) {
6294 GST_LOG_OBJECT (demux,
6295 "Stream #%d , checking if offset %" G_GUINT64_FORMAT
6296 " is a sample start", i, GST_BUFFER_OFFSET (inbuf));
6298 gst_qtdemux_find_index_for_given_media_offset_linear (demux,
6299 demux->streams[i], GST_BUFFER_OFFSET (inbuf));
6301 QtDemuxSample *sample = &demux->streams[i]->samples[res];
6302 GST_LOG_OBJECT (demux,
6303 "Checking if sample %d from stream %d is valid (offset:%"
6304 G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res, i,
6305 sample->offset, sample->size);
6306 if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
6307 GST_LOG_OBJECT (demux,
6308 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
6310 is_gap_input = TRUE;
6311 /* We can go back to standard playback mode */
6312 demux->state = QTDEMUX_STATE_MOVIE;
6313 /* Remember which sample this stream is at */
6314 demux->streams[i]->sample_index = res;
6315 /* Finally update all push-based values to the expected values */
6316 demux->neededbytes = demux->streams[i]->samples[res].size;
6317 demux->offset = GST_BUFFER_OFFSET (inbuf);
6319 demux->mdatsize - demux->offset + demux->mdatoffset;
6324 if (!is_gap_input) {
6325 /* Reset state if it's a real discont */
6326 demux->neededbytes = 16;
6327 demux->state = QTDEMUX_STATE_INITIAL;
6328 demux->offset = GST_BUFFER_OFFSET (inbuf);
6331 /* Reverse fragmented playback, need to flush all we have before
6332 * consuming a new fragment.
6333 * The samples array have the timestamps calculated by accumulating the
6334 * durations but this won't work for reverse playback of fragments as
6335 * the timestamps of a subsequent fragment should be smaller than the
6336 * previously received one. */
6337 if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
6338 gst_qtdemux_process_adapter (demux, TRUE);
6339 for (i = 0; i < demux->n_streams; i++)
6340 gst_qtdemux_stream_flush_samples_data (demux, demux->streams[i]);
6344 gst_adapter_push (demux->adapter, inbuf);
6346 GST_DEBUG_OBJECT (demux,
6347 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
6348 demux->neededbytes, gst_adapter_available (demux->adapter));
6350 return gst_qtdemux_process_adapter (demux, FALSE);
6353 static GstFlowReturn
6354 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
6356 GstFlowReturn ret = GST_FLOW_OK;
6358 /* we never really mean to buffer that much */
6359 if (demux->neededbytes == -1) {
6363 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
6364 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
6366 #ifndef GST_DISABLE_GST_DEBUG
6368 guint64 discont_offset, distance_from_discont;
6370 discont_offset = gst_adapter_offset_at_discont (demux->adapter);
6371 distance_from_discont =
6372 gst_adapter_distance_from_discont (demux->adapter);
6374 GST_DEBUG_OBJECT (demux,
6375 "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
6376 " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
6377 " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
6378 demux->offset, discont_offset, distance_from_discont);
6382 switch (demux->state) {
6383 case QTDEMUX_STATE_INITIAL:{
6388 gst_qtdemux_check_seekability (demux);
6390 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6392 /* get fourcc/length, set neededbytes */
6393 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
6395 gst_adapter_unmap (demux->adapter);
6397 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
6398 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
6400 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6401 (_("This file is invalid and cannot be played.")),
6402 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
6403 GST_FOURCC_ARGS (fourcc)));
6404 ret = GST_FLOW_ERROR;
6407 if (fourcc == FOURCC_mdat) {
6408 gint next_entry = next_entry_size (demux);
6409 if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
6410 /* we have the headers, start playback */
6411 demux->state = QTDEMUX_STATE_MOVIE;
6412 demux->neededbytes = next_entry;
6413 demux->mdatleft = size;
6414 demux->mdatsize = demux->mdatleft;
6416 /* no headers yet, try to get them */
6419 guint64 old, target;
6422 old = demux->offset;
6423 target = old + size;
6425 /* try to jump over the atom with a seek */
6426 /* only bother if it seems worth doing so,
6427 * and avoids possible upstream/server problems */
6428 if (demux->upstream_seekable &&
6429 demux->upstream_size > 4 * (1 << 20)) {
6430 res = qtdemux_seek_offset (demux, target);
6432 GST_DEBUG_OBJECT (demux, "skipping seek");
6437 GST_DEBUG_OBJECT (demux, "seek success");
6438 /* remember the offset fo the first mdat so we can seek back to it
6439 * after we have the headers */
6440 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
6441 demux->first_mdat = old;
6442 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
6445 /* seek worked, continue reading */
6446 demux->offset = target;
6447 demux->neededbytes = 16;
6448 demux->state = QTDEMUX_STATE_INITIAL;
6450 /* seek failed, need to buffer */
6451 demux->offset = old;
6452 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
6453 /* there may be multiple mdat (or alike) buffers */
6455 if (demux->mdatbuffer)
6456 bs = gst_buffer_get_size (demux->mdatbuffer);
6459 if (size + bs > 10 * (1 << 20))
6461 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
6462 demux->neededbytes = size;
6463 if (!demux->mdatbuffer)
6464 demux->mdatoffset = demux->offset;
6467 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
6468 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6469 (_("This file is invalid and cannot be played.")),
6470 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
6471 GST_FOURCC_ARGS (fourcc), size));
6472 ret = GST_FLOW_ERROR;
6475 /* this means we already started buffering and still no moov header,
6476 * let's continue buffering everything till we get moov */
6477 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
6478 || fourcc == FOURCC_moof))
6480 demux->neededbytes = size;
6481 demux->state = QTDEMUX_STATE_HEADER;
6485 case QTDEMUX_STATE_HEADER:{
6489 GST_DEBUG_OBJECT (demux, "In header");
6491 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6493 /* parse the header */
6494 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
6496 if (fourcc == FOURCC_moov) {
6499 /* in usual fragmented setup we could try to scan for more
6500 * and end up at the the moov (after mdat) again */
6501 if (demux->got_moov && demux->n_streams > 0 &&
6503 || demux->last_moov_offset == demux->offset)) {
6504 GST_DEBUG_OBJECT (demux,
6505 "Skipping moov atom as we have (this) one already");
6507 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
6509 if (demux->got_moov && demux->fragmented) {
6510 GST_DEBUG_OBJECT (demux,
6511 "Got a second moov, clean up data from old one");
6512 if (demux->moov_node_compressed) {
6513 g_node_destroy (demux->moov_node_compressed);
6514 if (demux->moov_node)
6515 g_free (demux->moov_node->data);
6517 demux->moov_node_compressed = NULL;
6518 if (demux->moov_node)
6519 g_node_destroy (demux->moov_node);
6520 demux->moov_node = NULL;
6522 /* prepare newsegment to send when streaming actually starts */
6523 if (!demux->pending_newsegment) {
6524 demux->pending_newsegment =
6525 gst_event_new_segment (&demux->segment);
6526 if (demux->segment_seqnum)
6527 gst_event_set_seqnum (demux->pending_newsegment,
6528 demux->segment_seqnum);
6532 demux->last_moov_offset = demux->offset;
6534 qtdemux_parse_moov (demux, data, demux->neededbytes);
6535 qtdemux_node_dump (demux, demux->moov_node);
6536 qtdemux_parse_tree (demux);
6537 qtdemux_prepare_streams (demux);
6538 if (!demux->got_moov)
6539 qtdemux_expose_streams (demux);
6542 for (n = 0; n < demux->n_streams; n++) {
6543 QtDemuxStream *stream = demux->streams[n];
6545 gst_qtdemux_configure_stream (demux, stream);
6549 demux->got_moov = TRUE;
6550 gst_qtdemux_check_send_pending_segment (demux);
6552 /* fragmented streams headers shouldn't contain edts atoms */
6553 if (!demux->fragmented) {
6554 for (n = 0; n < demux->n_streams; n++) {
6555 gst_qtdemux_stream_send_initial_gap_segments (demux,
6560 if (demux->moov_node_compressed) {
6561 g_node_destroy (demux->moov_node_compressed);
6562 g_free (demux->moov_node->data);
6564 demux->moov_node_compressed = NULL;
6565 g_node_destroy (demux->moov_node);
6566 demux->moov_node = NULL;
6567 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
6569 } else if (fourcc == FOURCC_moof) {
6570 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
6572 GstClockTime prev_pts;
6573 guint64 prev_offset;
6574 guint64 adapter_discont_offset, adapter_discont_dist;
6576 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
6579 * The timestamp of the moof buffer is relevant as some scenarios
6580 * won't have the initial timestamp in the atoms. Whenever a new
6581 * buffer has started, we get that buffer's PTS and use it as a base
6582 * timestamp for the trun entries.
6584 * To keep track of the current buffer timestamp and starting point
6585 * we use gst_adapter_prev_pts that gives us the PTS and the distance
6586 * from the beggining of the buffer, with the distance and demux->offset
6587 * we know if it is still the same buffer or not.
6589 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
6590 prev_offset = demux->offset - dist;
6591 if (demux->fragment_start_offset == -1
6592 || prev_offset > demux->fragment_start_offset) {
6593 demux->fragment_start_offset = prev_offset;
6594 demux->fragment_start = prev_pts;
6595 GST_DEBUG_OBJECT (demux,
6596 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
6597 GST_TIME_FORMAT, demux->fragment_start_offset,
6598 GST_TIME_ARGS (demux->fragment_start));
6601 /* We can't use prev_offset() here because this would require
6602 * upstream to set consistent and correct offsets on all buffers
6603 * since the discont. Nothing ever did that in the past and we
6604 * would break backwards compatibility here then.
6605 * Instead take the offset we had at the last discont and count
6606 * the bytes from there. This works with old code as there would
6607 * be no discont between moov and moof, and also works with
6608 * adaptivedemux which correctly sets offset and will set the
6609 * DISCONT flag accordingly when needed.
6611 * We also only do this for upstream TIME segments as otherwise
6612 * there are potential backwards compatibility problems with
6613 * seeking in PUSH mode and upstream providing inconsistent
6615 adapter_discont_offset =
6616 gst_adapter_offset_at_discont (demux->adapter);
6617 adapter_discont_dist =
6618 gst_adapter_distance_from_discont (demux->adapter);
6620 GST_DEBUG_OBJECT (demux,
6621 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
6622 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
6623 demux->offset, adapter_discont_offset, adapter_discont_dist);
6625 if (demux->upstream_format_is_time) {
6626 demux->moof_offset = adapter_discont_offset;
6627 if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
6628 demux->moof_offset += adapter_discont_dist;
6629 if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
6630 demux->moof_offset = demux->offset;
6632 demux->moof_offset = demux->offset;
6635 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
6636 demux->moof_offset, NULL)) {
6637 gst_adapter_unmap (demux->adapter);
6638 ret = GST_FLOW_ERROR;
6641 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
6642 if (demux->mss_mode && !demux->exposed) {
6643 if (!demux->pending_newsegment) {
6644 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
6645 demux->pending_newsegment =
6646 gst_event_new_segment (&demux->segment);
6647 if (demux->segment_seqnum)
6648 gst_event_set_seqnum (demux->pending_newsegment,
6649 demux->segment_seqnum);
6651 qtdemux_expose_streams (demux);
6654 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
6656 } else if (fourcc == FOURCC_ftyp) {
6657 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
6658 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
6659 } else if (fourcc == FOURCC_uuid) {
6660 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
6661 qtdemux_parse_uuid (demux, data, demux->neededbytes);
6662 } else if (fourcc == FOURCC_sidx) {
6663 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
6664 qtdemux_parse_sidx (demux, data, demux->neededbytes);
6668 /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
6671 /* [free] is a padding atom */
6672 GST_DEBUG_OBJECT (demux,
6673 "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
6674 GST_FOURCC_ARGS (fourcc));
6677 GST_WARNING_OBJECT (demux,
6678 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
6679 GST_FOURCC_ARGS (fourcc));
6680 /* Let's jump that one and go back to initial state */
6684 gst_adapter_unmap (demux->adapter);
6687 if (demux->mdatbuffer && demux->n_streams) {
6688 gsize remaining_data_size = 0;
6690 /* the mdat was before the header */
6691 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
6692 demux->n_streams, demux->mdatbuffer);
6693 /* restore our adapter/offset view of things with upstream;
6694 * put preceding buffered data ahead of current moov data.
6695 * This should also handle evil mdat, moov, mdat cases and alike */
6696 gst_adapter_flush (demux->adapter, demux->neededbytes);
6698 /* Store any remaining data after the mdat for later usage */
6699 remaining_data_size = gst_adapter_available (demux->adapter);
6700 if (remaining_data_size > 0) {
6701 g_assert (demux->restoredata_buffer == NULL);
6702 demux->restoredata_buffer =
6703 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
6704 demux->restoredata_offset = demux->offset + demux->neededbytes;
6705 GST_DEBUG_OBJECT (demux,
6706 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
6707 G_GUINT64_FORMAT, remaining_data_size,
6708 demux->restoredata_offset);
6711 gst_adapter_push (demux->adapter, demux->mdatbuffer);
6712 demux->mdatbuffer = NULL;
6713 demux->offset = demux->mdatoffset;
6714 demux->neededbytes = next_entry_size (demux);
6715 demux->state = QTDEMUX_STATE_MOVIE;
6716 demux->mdatleft = gst_adapter_available (demux->adapter);
6717 demux->mdatsize = demux->mdatleft;
6719 GST_DEBUG_OBJECT (demux, "Carrying on normally");
6720 gst_adapter_flush (demux->adapter, demux->neededbytes);
6722 /* only go back to the mdat if there are samples to play */
6723 if (demux->got_moov && demux->first_mdat != -1
6724 && has_next_entry (demux)) {
6727 /* we need to seek back */
6728 res = qtdemux_seek_offset (demux, demux->first_mdat);
6730 demux->offset = demux->first_mdat;
6732 GST_DEBUG_OBJECT (demux, "Seek back failed");
6735 demux->offset += demux->neededbytes;
6737 demux->neededbytes = 16;
6738 demux->state = QTDEMUX_STATE_INITIAL;
6743 case QTDEMUX_STATE_BUFFER_MDAT:{
6747 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
6749 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6750 gst_buffer_extract (buf, 0, fourcc, 4);
6751 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
6752 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
6753 if (demux->mdatbuffer)
6754 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
6756 demux->mdatbuffer = buf;
6757 demux->offset += demux->neededbytes;
6758 demux->neededbytes = 16;
6759 demux->state = QTDEMUX_STATE_INITIAL;
6760 gst_qtdemux_post_progress (demux, 1, 1);
6764 case QTDEMUX_STATE_MOVIE:{
6765 QtDemuxStream *stream = NULL;
6766 QtDemuxSample *sample;
6768 GstClockTime dts, pts, duration;
6771 GST_DEBUG_OBJECT (demux,
6772 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
6774 if (demux->fragmented) {
6775 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
6777 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
6778 /* if needed data starts within this atom,
6779 * then it should not exceed this atom */
6780 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
6781 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6782 (_("This file is invalid and cannot be played.")),
6783 ("sample data crosses atom boundary"));
6784 ret = GST_FLOW_ERROR;
6787 demux->mdatleft -= demux->neededbytes;
6789 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
6790 /* so we are dropping more than left in this atom */
6791 gst_qtdemux_drop_data (demux, demux->mdatleft);
6792 demux->mdatleft = 0;
6794 /* need to resume atom parsing so we do not miss any other pieces */
6795 demux->state = QTDEMUX_STATE_INITIAL;
6796 demux->neededbytes = 16;
6798 /* check if there was any stored post mdat data from previous buffers */
6799 if (demux->restoredata_buffer) {
6800 g_assert (gst_adapter_available (demux->adapter) == 0);
6802 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
6803 demux->restoredata_buffer = NULL;
6804 demux->offset = demux->restoredata_offset;
6811 if (demux->todrop) {
6812 if (demux->cenc_aux_info_offset > 0) {
6816 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
6817 data = gst_adapter_map (demux->adapter, demux->todrop);
6818 gst_byte_reader_init (&br, data + 8, demux->todrop);
6819 if (!qtdemux_parse_cenc_aux_info (demux, demux->streams[0], &br,
6820 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
6821 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
6822 ret = GST_FLOW_ERROR;
6823 gst_adapter_unmap (demux->adapter);
6824 g_free (demux->cenc_aux_info_sizes);
6825 demux->cenc_aux_info_sizes = NULL;
6828 demux->cenc_aux_info_offset = 0;
6829 g_free (demux->cenc_aux_info_sizes);
6830 demux->cenc_aux_info_sizes = NULL;
6831 gst_adapter_unmap (demux->adapter);
6833 gst_qtdemux_drop_data (demux, demux->todrop);
6837 /* initial newsegment sent here after having added pads,
6838 * possible others in sink_event */
6839 gst_qtdemux_check_send_pending_segment (demux);
6841 /* Figure out which stream this packet belongs to */
6842 for (i = 0; i < demux->n_streams; i++) {
6843 stream = demux->streams[i];
6844 if (stream->sample_index >= stream->n_samples)
6846 GST_LOG_OBJECT (demux,
6847 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
6848 " / size:%d)", i, stream->sample_index,
6849 stream->samples[stream->sample_index].offset,
6850 stream->samples[stream->sample_index].size);
6852 if (stream->samples[stream->sample_index].offset == demux->offset)
6856 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
6857 goto unknown_stream;
6859 gst_qtdemux_stream_check_and_change_stsd_index (demux, stream);
6861 if (stream->new_caps) {
6862 gst_qtdemux_configure_stream (demux, stream);
6865 /* Put data in a buffer, set timestamps, caps, ... */
6866 sample = &stream->samples[stream->sample_index];
6868 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
6869 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
6870 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
6872 dts = QTSAMPLE_DTS (stream, sample);
6873 pts = QTSAMPLE_PTS (stream, sample);
6874 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
6875 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
6877 /* check for segment end */
6878 if (G_UNLIKELY (demux->segment.stop != -1
6879 && demux->segment.stop <= pts && stream->on_keyframe)) {
6880 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
6881 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
6883 /* skip this data, stream is EOS */
6884 gst_adapter_flush (demux->adapter, demux->neededbytes);
6886 /* check if all streams are eos */
6888 for (i = 0; i < demux->n_streams; i++) {
6889 if (!STREAM_IS_EOS (demux->streams[i])) {
6895 if (ret == GST_FLOW_EOS) {
6896 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
6903 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6905 /* FIXME: should either be an assert or a plain check */
6906 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
6908 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
6909 dts, pts, duration, keyframe, dts, demux->offset);
6913 ret = gst_qtdemux_combine_flows (demux, stream, ret);
6915 /* skip this data, stream is EOS */
6916 gst_adapter_flush (demux->adapter, demux->neededbytes);
6919 stream->sample_index++;
6920 stream->offset_in_sample = 0;
6922 /* update current offset and figure out size of next buffer */
6923 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
6924 demux->offset, demux->neededbytes);
6925 demux->offset += demux->neededbytes;
6926 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
6929 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
6930 if (demux->fragmented) {
6931 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
6932 /* there may be more to follow, only finish this atom */
6933 demux->todrop = demux->mdatleft;
6934 demux->neededbytes = demux->todrop;
6939 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
6940 goto non_ok_unlinked_flow;
6949 /* when buffering movie data, at least show user something is happening */
6950 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
6951 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
6952 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
6953 demux->neededbytes);
6960 non_ok_unlinked_flow:
6962 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
6963 gst_flow_get_name (ret));
6968 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
6969 ret = GST_FLOW_ERROR;
6974 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
6980 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
6981 (NULL), ("qtdemuxer invalid state %d", demux->state));
6982 ret = GST_FLOW_ERROR;
6987 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
6988 (NULL), ("no 'moov' atom within the first 10 MB"));
6989 ret = GST_FLOW_ERROR;
6995 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
7000 query = gst_query_new_scheduling ();
7002 if (!gst_pad_peer_query (sinkpad, query)) {
7003 gst_query_unref (query);
7007 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
7008 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
7009 gst_query_unref (query);
7014 GST_DEBUG_OBJECT (sinkpad, "activating pull");
7015 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
7019 GST_DEBUG_OBJECT (sinkpad, "activating push");
7020 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
7025 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
7026 GstPadMode mode, gboolean active)
7029 GstQTDemux *demux = GST_QTDEMUX (parent);
7032 case GST_PAD_MODE_PUSH:
7033 demux->pullbased = FALSE;
7036 case GST_PAD_MODE_PULL:
7038 demux->pullbased = TRUE;
7039 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
7042 res = gst_pad_stop_task (sinkpad);
7054 qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
7060 memset (&z, 0, sizeof (z));
7065 if ((ret = inflateInit (&z)) != Z_OK) {
7066 GST_ERROR ("inflateInit() returned %d", ret);
7070 z.next_in = z_buffer;
7071 z.avail_in = z_length;
7073 buffer = (guint8 *) g_malloc (*length);
7074 z.avail_out = *length;
7075 z.next_out = (Bytef *) buffer;
7077 ret = inflate (&z, Z_NO_FLUSH);
7078 if (ret == Z_STREAM_END) {
7080 } else if (ret != Z_OK) {
7081 GST_WARNING ("inflate() returned %d", ret);
7086 buffer = (guint8 *) g_realloc (buffer, *length);
7087 z.next_out = (Bytef *) (buffer + z.total_out);
7088 z.avail_out += 4096;
7089 } while (z.avail_in > 0);
7091 if (ret != Z_STREAM_END) {
7096 *length = z.total_out;
7103 #endif /* HAVE_ZLIB */
7106 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
7110 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
7112 /* counts as header data */
7113 qtdemux->header_size += length;
7115 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
7116 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
7118 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
7125 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
7126 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
7127 if (dcom == NULL || cmvd == NULL)
7128 goto invalid_compression;
7130 dcom_len = QT_UINT32 (dcom->data);
7132 goto invalid_compression;
7134 method = QT_FOURCC ((guint8 *) dcom->data + 8);
7138 guint uncompressed_length;
7139 guint compressed_length;
7143 cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
7145 goto invalid_compression;
7147 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
7148 compressed_length = cmvd_len - 12;
7149 GST_LOG ("length = %u", uncompressed_length);
7152 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
7153 compressed_length, &uncompressed_length);
7156 qtdemux->moov_node_compressed = qtdemux->moov_node;
7157 qtdemux->moov_node = g_node_new (buf);
7159 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
7160 uncompressed_length);
7164 #endif /* HAVE_ZLIB */
7166 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
7167 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
7174 invalid_compression:
7176 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
7182 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
7185 while (G_UNLIKELY (buf < end)) {
7189 if (G_UNLIKELY (buf + 4 > end)) {
7190 GST_LOG_OBJECT (qtdemux, "buffer overrun");
7193 len = QT_UINT32 (buf);
7194 if (G_UNLIKELY (len == 0)) {
7195 GST_LOG_OBJECT (qtdemux, "empty container");
7198 if (G_UNLIKELY (len < 8)) {
7199 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
7202 if (G_UNLIKELY (len > (end - buf))) {
7203 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
7204 (gint) (end - buf));
7208 child = g_node_new ((guint8 *) buf);
7209 g_node_append (node, child);
7210 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
7211 qtdemux_parse_node (qtdemux, child, buf, len);
7219 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
7222 int len = QT_UINT32 (xdxt->data);
7223 guint8 *buf = xdxt->data;
7224 guint8 *end = buf + len;
7227 /* skip size and type */
7235 size = QT_UINT32 (buf);
7236 type = QT_FOURCC (buf + 4);
7238 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
7240 if (buf + size > end || size <= 0)
7246 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
7247 GST_FOURCC_ARGS (type));
7251 buffer = gst_buffer_new_and_alloc (size);
7252 gst_buffer_fill (buffer, 0, buf, size);
7253 stream->buffers = g_slist_append (stream->buffers, buffer);
7254 GST_LOG_OBJECT (qtdemux, "parsing theora header");
7257 buffer = gst_buffer_new_and_alloc (size);
7258 gst_buffer_fill (buffer, 0, buf, size);
7259 stream->buffers = g_slist_append (stream->buffers, buffer);
7260 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
7263 buffer = gst_buffer_new_and_alloc (size);
7264 gst_buffer_fill (buffer, 0, buf, size);
7265 stream->buffers = g_slist_append (stream->buffers, buffer);
7266 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
7269 GST_WARNING_OBJECT (qtdemux,
7270 "unknown theora cookie %" GST_FOURCC_FORMAT,
7271 GST_FOURCC_ARGS (type));
7280 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
7284 guint32 node_length = 0;
7285 const QtNodeType *type;
7288 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
7290 if (G_UNLIKELY (length < 8))
7291 goto not_enough_data;
7293 node_length = QT_UINT32 (buffer);
7294 fourcc = QT_FOURCC (buffer + 4);
7296 /* ignore empty nodes */
7297 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
7300 type = qtdemux_type_get (fourcc);
7302 end = buffer + length;
7304 GST_LOG_OBJECT (qtdemux,
7305 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
7306 GST_FOURCC_ARGS (fourcc), node_length, type->name);
7308 if (node_length > length)
7309 goto broken_atom_size;
7311 if (type->flags & QT_FLAG_CONTAINER) {
7312 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
7317 if (node_length < 20) {
7318 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
7321 GST_DEBUG_OBJECT (qtdemux,
7322 "parsing stsd (sample table, sample description) atom");
7323 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
7324 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7335 /* also read alac (or whatever) in stead of mp4a in the following,
7336 * since a similar layout is used in other cases as well */
7337 if (fourcc == FOURCC_mp4a)
7339 else if (fourcc == FOURCC_fLaC)
7344 /* There are two things we might encounter here: a true mp4a atom, and
7345 an mp4a entry in an stsd atom. The latter is what we're interested
7346 in, and it looks like an atom, but isn't really one. The true mp4a
7347 atom is short, so we detect it based on length here. */
7348 if (length < min_size) {
7349 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7350 GST_FOURCC_ARGS (fourcc));
7354 /* 'version' here is the sound sample description version. Types 0 and
7355 1 are documented in the QTFF reference, but type 2 is not: it's
7356 described in Apple header files instead (struct SoundDescriptionV2
7358 version = QT_UINT16 (buffer + 16);
7360 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
7361 GST_FOURCC_ARGS (fourcc), version);
7363 /* parse any esds descriptors */
7375 GST_WARNING_OBJECT (qtdemux,
7376 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
7377 GST_FOURCC_ARGS (fourcc), version);
7382 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7408 /* codec_data is contained inside these atoms, which all have
7409 * the same format. */
7410 /* video sample description size is 86 bytes without extension.
7411 * node_length have to be bigger than 86 bytes because video sample
7412 * description can include extenstions such as esds, fiel, glbl, etc. */
7413 if (node_length < 86) {
7414 GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
7415 " sample description length too short (%u < 86)",
7416 GST_FOURCC_ARGS (fourcc), node_length);
7420 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
7421 GST_FOURCC_ARGS (fourcc));
7423 /* version (2 bytes) : this is set to 0, unless a compressor has changed
7425 * revision level (2 bytes) : must be set to 0. */
7426 version = QT_UINT32 (buffer + 16);
7427 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
7429 /* compressor name : PASCAL string and informative purposes
7430 * first byte : the number of bytes to be displayed.
7431 * it has to be less than 32 because it is reserved
7432 * space of 32 bytes total including itself. */
7433 str_len = QT_UINT8 (buffer + 50);
7435 GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
7436 (char *) buffer + 51);
7438 GST_WARNING_OBJECT (qtdemux,
7439 "compressorname length too big (%u > 31)", str_len);
7441 GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
7443 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
7448 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
7449 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
7454 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
7455 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
7456 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7465 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7466 GST_FOURCC_ARGS (fourcc));
7470 version = QT_UINT32 (buffer + 12);
7471 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
7478 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
7483 if (length < offset) {
7484 GST_WARNING_OBJECT (qtdemux,
7485 "skipping too small %" GST_FOURCC_FORMAT " box",
7486 GST_FOURCC_ARGS (fourcc));
7489 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7495 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
7500 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
7505 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
7509 if (!strcmp (type->name, "unknown"))
7510 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
7514 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
7515 GST_FOURCC_ARGS (fourcc));
7521 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7522 (_("This file is corrupt and cannot be played.")),
7523 ("Not enough data for an atom header, got only %u bytes", length));
7528 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7529 (_("This file is corrupt and cannot be played.")),
7530 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
7531 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
7538 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
7542 guint32 child_fourcc;
7544 for (child = g_node_first_child (node); child;
7545 child = g_node_next_sibling (child)) {
7546 buffer = (guint8 *) child->data;
7548 child_fourcc = QT_FOURCC (buffer + 4);
7550 if (G_UNLIKELY (child_fourcc == fourcc)) {
7558 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
7559 GstByteReader * parser)
7563 guint32 child_fourcc, child_len;
7565 for (child = g_node_first_child (node); child;
7566 child = g_node_next_sibling (child)) {
7567 buffer = (guint8 *) child->data;
7569 child_len = QT_UINT32 (buffer);
7570 child_fourcc = QT_FOURCC (buffer + 4);
7572 if (G_UNLIKELY (child_fourcc == fourcc)) {
7573 if (G_UNLIKELY (child_len < (4 + 4)))
7575 /* FIXME: must verify if atom length < parent atom length */
7576 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7584 qtdemux_tree_get_child_by_index (GNode * node, guint index)
7586 return g_node_nth_child (node, index);
7590 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
7591 GstByteReader * parser)
7595 guint32 child_fourcc, child_len;
7597 for (child = g_node_next_sibling (node); child;
7598 child = g_node_next_sibling (child)) {
7599 buffer = (guint8 *) child->data;
7601 child_fourcc = QT_FOURCC (buffer + 4);
7603 if (child_fourcc == fourcc) {
7605 child_len = QT_UINT32 (buffer);
7606 if (G_UNLIKELY (child_len < (4 + 4)))
7608 /* FIXME: must verify if atom length < parent atom length */
7609 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7618 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
7620 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
7624 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
7626 /* FIXME: This can only reliably work if demuxers have a
7627 * separate streaming thread per srcpad. This should be
7628 * done in a demuxer base class, which integrates parts
7631 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
7636 query = gst_query_new_allocation (stream->caps, FALSE);
7638 if (!gst_pad_peer_query (stream->pad, query)) {
7639 /* not a problem, just debug a little */
7640 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
7643 if (stream->allocator)
7644 gst_object_unref (stream->allocator);
7646 if (gst_query_get_n_allocation_params (query) > 0) {
7647 /* try the allocator */
7648 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
7650 stream->use_allocator = TRUE;
7652 stream->allocator = NULL;
7653 gst_allocation_params_init (&stream->params);
7654 stream->use_allocator = FALSE;
7656 gst_query_unref (query);
7661 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
7662 QtDemuxStream * stream)
7665 const gchar *selected_system;
7667 g_return_val_if_fail (qtdemux != NULL, FALSE);
7668 g_return_val_if_fail (stream != NULL, FALSE);
7669 g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1,
7672 if (stream->protection_scheme_type != FOURCC_cenc) {
7673 GST_ERROR_OBJECT (qtdemux, "unsupported protection scheme");
7676 if (qtdemux->protection_system_ids == NULL) {
7677 GST_ERROR_OBJECT (qtdemux, "stream is protected using cenc, but no "
7678 "cenc protection system information has been found");
7681 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
7682 selected_system = gst_protection_select_system ((const gchar **)
7683 qtdemux->protection_system_ids->pdata);
7684 g_ptr_array_remove_index (qtdemux->protection_system_ids,
7685 qtdemux->protection_system_ids->len - 1);
7686 if (!selected_system) {
7687 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
7688 "suitable decryptor element has been found");
7692 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
7693 if (!gst_structure_has_name (s, "application/x-cenc")) {
7694 gst_structure_set (s,
7695 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
7696 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
7698 gst_structure_set_name (s, "application/x-cenc");
7704 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
7706 if (stream->subtype == FOURCC_vide) {
7707 /* fps is calculated base on the duration of the average framerate since
7708 * qt does not have a fixed framerate. */
7709 gboolean fps_available = TRUE;
7711 if ((stream->n_samples == 1) && (stream->first_duration == 0)) {
7713 CUR_STREAM (stream)->fps_n = 0;
7714 CUR_STREAM (stream)->fps_d = 1;
7716 if (stream->duration == 0 || stream->n_samples < 2) {
7717 CUR_STREAM (stream)->fps_n = stream->timescale;
7718 CUR_STREAM (stream)->fps_d = 1;
7719 fps_available = FALSE;
7721 GstClockTime avg_duration;
7725 /* duration and n_samples can be updated for fragmented format
7726 * so, framerate of fragmented format is calculated using data in a moof */
7727 if (qtdemux->fragmented && stream->n_samples_moof > 0
7728 && stream->duration_moof > 0) {
7729 n_samples = stream->n_samples_moof;
7730 duration = stream->duration_moof;
7732 n_samples = stream->n_samples;
7733 duration = stream->duration;
7736 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
7737 /* stream->duration is guint64, timescale, n_samples are guint32 */
7739 gst_util_uint64_scale_round (duration -
7740 stream->first_duration, GST_SECOND,
7741 (guint64) (stream->timescale) * (n_samples - 1));
7743 GST_LOG_OBJECT (qtdemux,
7744 "Calculating avg sample duration based on stream (or moof) duration %"
7746 " minus first sample %u, leaving %d samples gives %"
7747 GST_TIME_FORMAT, duration, stream->first_duration,
7748 n_samples - 1, GST_TIME_ARGS (avg_duration));
7750 gst_video_guess_framerate (avg_duration, &CUR_STREAM (stream)->fps_n,
7751 &CUR_STREAM (stream)->fps_d);
7753 GST_DEBUG_OBJECT (qtdemux,
7754 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
7755 stream->timescale, CUR_STREAM (stream)->fps_n,
7756 CUR_STREAM (stream)->fps_d);
7760 if (CUR_STREAM (stream)->caps) {
7761 CUR_STREAM (stream)->caps =
7762 gst_caps_make_writable (CUR_STREAM (stream)->caps);
7764 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7765 "width", G_TYPE_INT, CUR_STREAM (stream)->width,
7766 "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL);
7768 /* set framerate if calculated framerate is reliable */
7769 if (fps_available) {
7770 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7771 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
7772 CUR_STREAM (stream)->fps_d, NULL);
7775 /* calculate pixel-aspect-ratio using display width and height */
7776 GST_DEBUG_OBJECT (qtdemux,
7777 "video size %dx%d, target display size %dx%d",
7778 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height,
7779 stream->display_width, stream->display_height);
7780 /* qt file might have pasp atom */
7781 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
7782 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w,
7783 CUR_STREAM (stream)->par_h);
7784 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
7785 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
7786 CUR_STREAM (stream)->par_h, NULL);
7787 } else if (stream->display_width > 0 && stream->display_height > 0
7788 && CUR_STREAM (stream)->width > 0
7789 && CUR_STREAM (stream)->height > 0) {
7792 /* calculate the pixel aspect ratio using the display and pixel w/h */
7793 n = stream->display_width * CUR_STREAM (stream)->height;
7794 d = stream->display_height * CUR_STREAM (stream)->width;
7797 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
7798 CUR_STREAM (stream)->par_w = n;
7799 CUR_STREAM (stream)->par_h = d;
7800 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
7801 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
7802 CUR_STREAM (stream)->par_h, NULL);
7805 if (CUR_STREAM (stream)->interlace_mode > 0) {
7806 if (CUR_STREAM (stream)->interlace_mode == 1) {
7807 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
7808 G_TYPE_STRING, "progressive", NULL);
7809 } else if (CUR_STREAM (stream)->interlace_mode == 2) {
7810 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
7811 G_TYPE_STRING, "interleaved", NULL);
7812 if (CUR_STREAM (stream)->field_order == 9) {
7813 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
7814 G_TYPE_STRING, "top-field-first", NULL);
7815 } else if (CUR_STREAM (stream)->field_order == 14) {
7816 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
7817 G_TYPE_STRING, "bottom-field-first", NULL);
7822 /* Create incomplete colorimetry here if needed */
7823 if (CUR_STREAM (stream)->colorimetry.range ||
7824 CUR_STREAM (stream)->colorimetry.matrix ||
7825 CUR_STREAM (stream)->colorimetry.transfer
7826 || CUR_STREAM (stream)->colorimetry.primaries) {
7827 gchar *colorimetry =
7828 gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry);
7829 gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry",
7830 G_TYPE_STRING, colorimetry, NULL);
7831 g_free (colorimetry);
7834 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
7835 guint par_w = 1, par_h = 1;
7837 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
7838 par_w = CUR_STREAM (stream)->par_w;
7839 par_h = CUR_STREAM (stream)->par_h;
7842 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
7843 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w,
7845 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
7848 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7849 "multiview-mode", G_TYPE_STRING,
7850 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
7851 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
7852 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
7857 else if (stream->subtype == FOURCC_soun) {
7858 if (CUR_STREAM (stream)->caps) {
7859 CUR_STREAM (stream)->caps =
7860 gst_caps_make_writable (CUR_STREAM (stream)->caps);
7861 if (CUR_STREAM (stream)->rate > 0)
7862 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7863 "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL);
7864 if (CUR_STREAM (stream)->n_channels > 0)
7865 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7866 "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL);
7867 if (CUR_STREAM (stream)->n_channels > 2) {
7868 /* FIXME: Need to parse the 'chan' atom to get channel layouts
7869 * correctly; this is just the minimum we can do - assume
7870 * we don't actually have any channel positions. */
7871 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7872 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
7878 GstCaps *prev_caps = NULL;
7880 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
7881 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
7882 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
7883 gst_pad_set_active (stream->pad, TRUE);
7885 gst_pad_use_fixed_caps (stream->pad);
7887 if (stream->protected) {
7888 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
7889 GST_ERROR_OBJECT (qtdemux,
7890 "Failed to configure protected stream caps.");
7895 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
7896 CUR_STREAM (stream)->caps);
7897 if (stream->new_stream) {
7900 GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
7903 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
7906 gst_event_parse_stream_flags (event, &stream_flags);
7907 if (gst_event_parse_group_id (event, &qtdemux->group_id))
7908 qtdemux->have_group_id = TRUE;
7910 qtdemux->have_group_id = FALSE;
7911 gst_event_unref (event);
7912 } else if (!qtdemux->have_group_id) {
7913 qtdemux->have_group_id = TRUE;
7914 qtdemux->group_id = gst_util_group_id_next ();
7917 stream->new_stream = FALSE;
7919 gst_pad_create_stream_id_printf (stream->pad,
7920 GST_ELEMENT_CAST (qtdemux), "%03u", stream->track_id);
7921 event = gst_event_new_stream_start (stream_id);
7922 if (qtdemux->have_group_id)
7923 gst_event_set_group_id (event, qtdemux->group_id);
7924 if (stream->disabled)
7925 stream_flags |= GST_STREAM_FLAG_UNSELECT;
7926 if (CUR_STREAM (stream)->sparse) {
7927 stream_flags |= GST_STREAM_FLAG_SPARSE;
7929 stream_flags &= ~GST_STREAM_FLAG_SPARSE;
7931 gst_event_set_stream_flags (event, stream_flags);
7932 gst_pad_push_event (stream->pad, event);
7936 prev_caps = gst_pad_get_current_caps (stream->pad);
7938 if (CUR_STREAM (stream)->caps) {
7940 || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) {
7941 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
7942 CUR_STREAM (stream)->caps);
7943 gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps);
7945 GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
7948 GST_WARNING_OBJECT (qtdemux, "stream without caps");
7952 gst_caps_unref (prev_caps);
7953 stream->new_caps = FALSE;
7959 gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
7960 QtDemuxStream * stream)
7962 if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id)
7965 GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'",
7966 stream->cur_stsd_entry_index, stream->stsd_sample_description_id);
7967 stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
7968 stream->new_caps = TRUE;
7972 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
7973 QtDemuxStream * stream, GstTagList * list)
7975 gboolean ret = TRUE;
7976 /* consistent default for push based mode */
7977 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
7979 if (stream->subtype == FOURCC_vide) {
7980 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
7983 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
7986 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7987 gst_object_unref (stream->pad);
7993 qtdemux->n_video_streams++;
7994 } else if (stream->subtype == FOURCC_soun) {
7995 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
7998 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
8000 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8001 gst_object_unref (stream->pad);
8006 qtdemux->n_audio_streams++;
8007 } else if (stream->subtype == FOURCC_strm) {
8008 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
8009 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
8010 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
8011 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
8014 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
8016 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8017 gst_object_unref (stream->pad);
8022 qtdemux->n_sub_streams++;
8023 } else if (CUR_STREAM (stream)->caps) {
8024 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8027 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8029 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8030 gst_object_unref (stream->pad);
8035 qtdemux->n_video_streams++;
8037 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
8044 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
8045 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
8046 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
8047 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
8049 if (stream->stream_tags)
8050 gst_tag_list_unref (stream->stream_tags);
8051 stream->stream_tags = list;
8053 /* global tags go on each pad anyway */
8054 stream->send_global_tags = TRUE;
8055 /* send upstream GST_EVENT_PROTECTION events that were received before
8056 this source pad was created */
8057 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
8058 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
8062 gst_tag_list_unref (list);
8066 /* find next atom with @fourcc starting at @offset */
8067 static GstFlowReturn
8068 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
8069 guint64 * length, guint32 fourcc)
8075 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
8076 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
8082 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
8083 if (G_UNLIKELY (ret != GST_FLOW_OK))
8085 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
8088 gst_buffer_unref (buf);
8091 gst_buffer_map (buf, &map, GST_MAP_READ);
8092 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
8093 gst_buffer_unmap (buf, &map);
8094 gst_buffer_unref (buf);
8096 if (G_UNLIKELY (*length == 0)) {
8097 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
8098 ret = GST_FLOW_ERROR;
8102 if (lfourcc == fourcc) {
8103 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
8107 GST_LOG_OBJECT (qtdemux,
8108 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
8109 GST_FOURCC_ARGS (fourcc), *offset);
8118 /* might simply have had last one */
8119 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
8124 /* should only do something in pull mode */
8125 /* call with OBJECT lock */
8126 static GstFlowReturn
8127 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
8129 guint64 length, offset;
8130 GstBuffer *buf = NULL;
8131 GstFlowReturn ret = GST_FLOW_OK;
8132 GstFlowReturn res = GST_FLOW_OK;
8135 offset = qtdemux->moof_offset;
8136 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
8139 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8140 return GST_FLOW_EOS;
8143 /* best not do pull etc with lock held */
8144 GST_OBJECT_UNLOCK (qtdemux);
8146 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8147 if (ret != GST_FLOW_OK)
8150 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
8151 if (G_UNLIKELY (ret != GST_FLOW_OK))
8153 gst_buffer_map (buf, &map, GST_MAP_READ);
8154 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
8155 gst_buffer_unmap (buf, &map);
8156 gst_buffer_unref (buf);
8161 gst_buffer_unmap (buf, &map);
8162 gst_buffer_unref (buf);
8166 /* look for next moof */
8167 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8168 if (G_UNLIKELY (ret != GST_FLOW_OK))
8172 GST_OBJECT_LOCK (qtdemux);
8174 qtdemux->moof_offset = offset;
8180 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
8182 res = GST_FLOW_ERROR;
8187 /* maybe upstream temporarily flushing */
8188 if (ret != GST_FLOW_FLUSHING) {
8189 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8192 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
8193 /* resume at current position next time */
8200 /* initialise bytereaders for stbl sub-atoms */
8202 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
8204 stream->stbl_index = -1; /* no samples have yet been parsed */
8205 stream->sample_index = -1;
8207 /* time-to-sample atom */
8208 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
8211 /* copy atom data into a new buffer for later use */
8212 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
8214 /* skip version + flags */
8215 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
8216 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
8218 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
8220 /* make sure there's enough data */
8221 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
8222 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
8223 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
8224 stream->n_sample_times);
8225 if (!stream->n_sample_times)
8229 /* sync sample atom */
8230 stream->stps_present = FALSE;
8231 if ((stream->stss_present =
8232 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
8233 &stream->stss) ? TRUE : FALSE) == TRUE) {
8234 /* copy atom data into a new buffer for later use */
8235 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
8237 /* skip version + flags */
8238 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
8239 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
8242 if (stream->n_sample_syncs) {
8243 /* make sure there's enough data */
8244 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
8248 /* partial sync sample atom */
8249 if ((stream->stps_present =
8250 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
8251 &stream->stps) ? TRUE : FALSE) == TRUE) {
8252 /* copy atom data into a new buffer for later use */
8253 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
8255 /* skip version + flags */
8256 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
8257 !gst_byte_reader_get_uint32_be (&stream->stps,
8258 &stream->n_sample_partial_syncs))
8261 /* if there are no entries, the stss table contains the real
8263 if (stream->n_sample_partial_syncs) {
8264 /* make sure there's enough data */
8265 if (!qt_atom_parser_has_chunks (&stream->stps,
8266 stream->n_sample_partial_syncs, 4))
8273 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
8276 /* copy atom data into a new buffer for later use */
8277 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
8279 /* skip version + flags */
8280 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
8281 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
8284 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
8287 if (!stream->n_samples)
8290 /* sample-to-chunk atom */
8291 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
8294 /* copy atom data into a new buffer for later use */
8295 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
8297 /* skip version + flags */
8298 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
8299 !gst_byte_reader_get_uint32_be (&stream->stsc,
8300 &stream->n_samples_per_chunk))
8303 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
8304 stream->n_samples_per_chunk);
8306 /* make sure there's enough data */
8307 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
8313 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
8314 stream->co_size = sizeof (guint32);
8315 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
8317 stream->co_size = sizeof (guint64);
8321 /* copy atom data into a new buffer for later use */
8322 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
8324 /* skip version + flags */
8325 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
8328 /* chunks_are_samples == TRUE means treat chunks as samples */
8329 stream->chunks_are_samples = stream->sample_size
8330 && !CUR_STREAM (stream)->sampled;
8331 if (stream->chunks_are_samples) {
8332 /* treat chunks as samples */
8333 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
8336 /* skip number of entries */
8337 if (!gst_byte_reader_skip (&stream->stco, 4))
8340 /* make sure there are enough data in the stsz atom */
8341 if (!stream->sample_size) {
8342 /* different sizes for each sample */
8343 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
8348 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
8349 stream->n_samples, (guint) sizeof (QtDemuxSample),
8350 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
8352 if (stream->n_samples >=
8353 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
8354 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
8355 "be larger than %uMB (broken file?)", stream->n_samples,
8356 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
8360 g_assert (stream->samples == NULL);
8361 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
8362 if (!stream->samples) {
8363 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
8368 /* composition time-to-sample */
8369 if ((stream->ctts_present =
8370 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
8371 &stream->ctts) ? TRUE : FALSE) == TRUE) {
8372 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
8374 /* copy atom data into a new buffer for later use */
8375 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
8377 /* skip version + flags */
8378 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
8379 || !gst_byte_reader_get_uint32_be (&stream->ctts,
8380 &stream->n_composition_times))
8383 /* make sure there's enough data */
8384 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
8388 /* This is optional, if missing we iterate the ctts */
8389 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
8390 if (!gst_byte_reader_skip (&cslg, 1 + 3)
8391 || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
8392 g_free ((gpointer) cslg.data);
8396 gint32 cslg_least = 0;
8397 guint num_entries, pos;
8400 pos = gst_byte_reader_get_pos (&stream->ctts);
8401 num_entries = stream->n_composition_times;
8403 stream->cslg_shift = 0;
8405 for (i = 0; i < num_entries; i++) {
8408 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
8409 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8411 if (offset < cslg_least)
8412 cslg_least = offset;
8416 stream->cslg_shift = ABS (cslg_least);
8418 stream->cslg_shift = 0;
8420 /* reset the reader so we can generate sample table */
8421 gst_byte_reader_set_pos (&stream->ctts, pos);
8424 /* Ensure the cslg_shift value is consistent so we can use it
8425 * unconditionnally to produce TS and Segment */
8426 stream->cslg_shift = 0;
8433 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8434 (_("This file is corrupt and cannot be played.")), (NULL));
8439 gst_qtdemux_stbl_free (stream);
8440 if (!qtdemux->fragmented) {
8441 /* not quite good */
8442 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
8445 /* may pick up samples elsewhere */
8451 /* collect samples from the next sample to be parsed up to sample @n for @stream
8452 * by reading the info from @stbl
8454 * This code can be executed from both the streaming thread and the seeking
8455 * thread so it takes the object lock to protect itself
8458 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
8461 QtDemuxSample *samples, *first, *cur, *last;
8462 guint32 n_samples_per_chunk;
8465 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
8466 GST_FOURCC_FORMAT ", pad %s",
8467 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
8468 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
8470 n_samples = stream->n_samples;
8473 goto out_of_samples;
8475 GST_OBJECT_LOCK (qtdemux);
8476 if (n <= stream->stbl_index)
8477 goto already_parsed;
8479 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
8481 if (!stream->stsz.data) {
8482 /* so we already parsed and passed all the moov samples;
8483 * onto fragmented ones */
8484 g_assert (qtdemux->fragmented);
8488 /* pointer to the sample table */
8489 samples = stream->samples;
8491 /* starts from -1, moves to the next sample index to parse */
8492 stream->stbl_index++;
8494 /* keep track of the first and last sample to fill */
8495 first = &samples[stream->stbl_index];
8498 if (!stream->chunks_are_samples) {
8499 /* set the sample sizes */
8500 if (stream->sample_size == 0) {
8501 /* different sizes for each sample */
8502 for (cur = first; cur <= last; cur++) {
8503 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
8504 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
8505 (guint) (cur - samples), cur->size);
8508 /* samples have the same size */
8509 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
8510 for (cur = first; cur <= last; cur++)
8511 cur->size = stream->sample_size;
8515 n_samples_per_chunk = stream->n_samples_per_chunk;
8518 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
8521 if (stream->stsc_chunk_index >= stream->last_chunk
8522 || stream->stsc_chunk_index < stream->first_chunk) {
8523 stream->first_chunk =
8524 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8525 stream->samples_per_chunk =
8526 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8528 stream->stsd_sample_description_id =
8529 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
8531 /* chunk numbers are counted from 1 it seems */
8532 if (G_UNLIKELY (stream->first_chunk == 0))
8535 --stream->first_chunk;
8537 /* the last chunk of each entry is calculated by taking the first chunk
8538 * of the next entry; except if there is no next, where we fake it with
8540 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
8541 stream->last_chunk = G_MAXUINT32;
8543 stream->last_chunk =
8544 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
8545 if (G_UNLIKELY (stream->last_chunk == 0))
8548 --stream->last_chunk;
8551 GST_LOG_OBJECT (qtdemux,
8552 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
8553 "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
8554 stream->samples_per_chunk, stream->stsd_sample_description_id);
8556 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
8559 if (stream->last_chunk != G_MAXUINT32) {
8560 if (!qt_atom_parser_peek_sub (&stream->stco,
8561 stream->first_chunk * stream->co_size,
8562 (stream->last_chunk - stream->first_chunk) * stream->co_size,
8567 stream->co_chunk = stream->stco;
8568 if (!gst_byte_reader_skip (&stream->co_chunk,
8569 stream->first_chunk * stream->co_size))
8573 stream->stsc_chunk_index = stream->first_chunk;
8576 last_chunk = stream->last_chunk;
8578 if (stream->chunks_are_samples) {
8579 cur = &samples[stream->stsc_chunk_index];
8581 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8584 stream->stsc_chunk_index = j;
8589 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
8592 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
8593 "%" G_GUINT64_FORMAT, j, cur->offset);
8595 if (CUR_STREAM (stream)->samples_per_frame > 0 &&
8596 CUR_STREAM (stream)->bytes_per_frame > 0) {
8598 (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
8599 CUR_STREAM (stream)->samples_per_frame *
8600 CUR_STREAM (stream)->bytes_per_frame;
8602 cur->size = stream->samples_per_chunk;
8605 GST_DEBUG_OBJECT (qtdemux,
8606 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
8607 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
8608 stream->stco_sample_index)), cur->size);
8610 cur->timestamp = stream->stco_sample_index;
8611 cur->duration = stream->samples_per_chunk;
8612 cur->keyframe = TRUE;
8615 stream->stco_sample_index += stream->samples_per_chunk;
8617 stream->stsc_chunk_index = j;
8619 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8620 guint32 samples_per_chunk;
8621 guint64 chunk_offset;
8623 if (!stream->stsc_sample_index
8624 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
8625 &stream->chunk_offset))
8628 samples_per_chunk = stream->samples_per_chunk;
8629 chunk_offset = stream->chunk_offset;
8631 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
8632 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
8633 G_GUINT64_FORMAT " and size %d",
8634 (guint) (cur - samples), chunk_offset, cur->size);
8636 cur->offset = chunk_offset;
8637 chunk_offset += cur->size;
8640 if (G_UNLIKELY (cur > last)) {
8642 stream->stsc_sample_index = k + 1;
8643 stream->chunk_offset = chunk_offset;
8644 stream->stsc_chunk_index = j;
8648 stream->stsc_sample_index = 0;
8650 stream->stsc_chunk_index = j;
8652 stream->stsc_index++;
8655 if (stream->chunks_are_samples)
8659 guint32 n_sample_times;
8661 n_sample_times = stream->n_sample_times;
8664 for (i = stream->stts_index; i < n_sample_times; i++) {
8665 guint32 stts_samples;
8666 gint32 stts_duration;
8669 if (stream->stts_sample_index >= stream->stts_samples
8670 || !stream->stts_sample_index) {
8672 stream->stts_samples =
8673 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8674 stream->stts_duration =
8675 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8677 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
8678 i, stream->stts_samples, stream->stts_duration);
8680 stream->stts_sample_index = 0;
8683 stts_samples = stream->stts_samples;
8684 stts_duration = stream->stts_duration;
8685 stts_time = stream->stts_time;
8687 for (j = stream->stts_sample_index; j < stts_samples; j++) {
8688 GST_DEBUG_OBJECT (qtdemux,
8689 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
8690 (guint) (cur - samples), j,
8691 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
8693 cur->timestamp = stts_time;
8694 cur->duration = stts_duration;
8696 /* avoid 32-bit wrap-around,
8697 * but still mind possible 'negative' duration */
8698 stts_time += (gint64) stts_duration;
8701 if (G_UNLIKELY (cur > last)) {
8703 stream->stts_time = stts_time;
8704 stream->stts_sample_index = j + 1;
8705 if (stream->stts_sample_index >= stream->stts_samples)
8706 stream->stts_index++;
8710 stream->stts_sample_index = 0;
8711 stream->stts_time = stts_time;
8712 stream->stts_index++;
8714 /* fill up empty timestamps with the last timestamp, this can happen when
8715 * the last samples do not decode and so we don't have timestamps for them.
8716 * We however look at the last timestamp to estimate the track length so we
8717 * need something in here. */
8718 for (; cur < last; cur++) {
8719 GST_DEBUG_OBJECT (qtdemux,
8720 "fill sample %d: timestamp %" GST_TIME_FORMAT,
8721 (guint) (cur - samples),
8722 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
8723 cur->timestamp = stream->stts_time;
8729 /* sample sync, can be NULL */
8730 if (stream->stss_present == TRUE) {
8731 guint32 n_sample_syncs;
8733 n_sample_syncs = stream->n_sample_syncs;
8735 if (!n_sample_syncs) {
8736 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
8737 stream->all_keyframe = TRUE;
8739 for (i = stream->stss_index; i < n_sample_syncs; i++) {
8740 /* note that the first sample is index 1, not 0 */
8743 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
8745 if (G_LIKELY (index > 0 && index <= n_samples)) {
8747 samples[index].keyframe = TRUE;
8748 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8749 /* and exit if we have enough samples */
8750 if (G_UNLIKELY (index >= n)) {
8757 stream->stss_index = i;
8760 /* stps marks partial sync frames like open GOP I-Frames */
8761 if (stream->stps_present == TRUE) {
8762 guint32 n_sample_partial_syncs;
8764 n_sample_partial_syncs = stream->n_sample_partial_syncs;
8766 /* if there are no entries, the stss table contains the real
8768 if (n_sample_partial_syncs) {
8769 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
8770 /* note that the first sample is index 1, not 0 */
8773 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
8775 if (G_LIKELY (index > 0 && index <= n_samples)) {
8777 samples[index].keyframe = TRUE;
8778 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8779 /* and exit if we have enough samples */
8780 if (G_UNLIKELY (index >= n)) {
8787 stream->stps_index = i;
8791 /* no stss, all samples are keyframes */
8792 stream->all_keyframe = TRUE;
8793 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
8798 /* composition time to sample */
8799 if (stream->ctts_present == TRUE) {
8800 guint32 n_composition_times;
8802 gint32 ctts_soffset;
8804 /* Fill in the pts_offsets */
8806 n_composition_times = stream->n_composition_times;
8808 for (i = stream->ctts_index; i < n_composition_times; i++) {
8809 if (stream->ctts_sample_index >= stream->ctts_count
8810 || !stream->ctts_sample_index) {
8811 stream->ctts_count =
8812 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
8813 stream->ctts_soffset =
8814 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8815 stream->ctts_sample_index = 0;
8818 ctts_count = stream->ctts_count;
8819 ctts_soffset = stream->ctts_soffset;
8821 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
8822 cur->pts_offset = ctts_soffset;
8825 if (G_UNLIKELY (cur > last)) {
8827 stream->ctts_sample_index = j + 1;
8831 stream->ctts_sample_index = 0;
8832 stream->ctts_index++;
8836 stream->stbl_index = n;
8837 /* if index has been completely parsed, free data that is no-longer needed */
8838 if (n + 1 == stream->n_samples) {
8839 gst_qtdemux_stbl_free (stream);
8840 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
8841 if (qtdemux->pullbased) {
8842 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
8843 while (n + 1 == stream->n_samples)
8844 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
8848 GST_OBJECT_UNLOCK (qtdemux);
8855 GST_LOG_OBJECT (qtdemux,
8856 "Tried to parse up to sample %u but this sample has already been parsed",
8858 /* if fragmented, there may be more */
8859 if (qtdemux->fragmented && n == stream->stbl_index)
8861 GST_OBJECT_UNLOCK (qtdemux);
8867 GST_LOG_OBJECT (qtdemux,
8868 "Tried to parse up to sample %u but there are only %u samples", n + 1,
8870 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8871 (_("This file is corrupt and cannot be played.")), (NULL));
8876 GST_OBJECT_UNLOCK (qtdemux);
8877 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8878 (_("This file is corrupt and cannot be played.")), (NULL));
8883 /* collect all segment info for @stream.
8886 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
8890 /* accept edts if they contain gaps at start and there is only
8891 * one media segment */
8892 gboolean allow_pushbased_edts = TRUE;
8893 gint media_segments_count = 0;
8895 /* parse and prepare segment info from the edit list */
8896 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
8897 stream->n_segments = 0;
8898 stream->segments = NULL;
8899 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
8902 gint i, count, entry_size;
8905 const guint8 *buffer;
8909 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
8910 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
8913 buffer = elst->data;
8915 size = QT_UINT32 (buffer);
8916 /* version, flags, n_segments */
8918 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
8921 version = QT_UINT8 (buffer + 8);
8922 entry_size = (version == 1) ? 20 : 12;
8924 n_segments = QT_UINT32 (buffer + 12);
8926 if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
8927 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
8931 /* we might allocate a bit too much, at least allocate 1 segment */
8932 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
8934 /* segments always start from 0 */
8939 for (i = 0; i < n_segments; i++) {
8942 gboolean time_valid = TRUE;
8943 QtDemuxSegment *segment;
8945 GstClockTime media_start = GST_CLOCK_TIME_NONE;
8948 media_time = QT_UINT64 (buffer + 8);
8949 duration = QT_UINT64 (buffer);
8950 if (media_time == G_MAXUINT64)
8953 media_time = QT_UINT32 (buffer + 4);
8954 duration = QT_UINT32 (buffer);
8955 if (media_time == G_MAXUINT32)
8960 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
8962 segment = &stream->segments[count++];
8964 /* time and duration expressed in global timescale */
8965 segment->time = stime;
8966 /* add non scaled values so we don't cause roundoff errors */
8967 if (duration || media_start == GST_CLOCK_TIME_NONE) {
8969 stime = QTTIME_TO_GSTTIME (qtdemux, time);
8970 segment->duration = stime - segment->time;
8972 /* zero duration does not imply media_start == media_stop
8973 * but, only specify media_start.*/
8974 stime = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
8975 if (GST_CLOCK_TIME_IS_VALID (stime) && time_valid
8976 && stime >= media_start) {
8977 segment->duration = stime - media_start;
8979 segment->duration = GST_CLOCK_TIME_NONE;
8982 segment->stop_time = stime;
8984 segment->trak_media_start = media_time;
8985 /* media_time expressed in stream timescale */
8987 segment->media_start = media_start;
8988 segment->media_stop = segment->media_start + segment->duration;
8989 media_segments_count++;
8991 segment->media_start = GST_CLOCK_TIME_NONE;
8992 segment->media_stop = GST_CLOCK_TIME_NONE;
8994 rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
8996 if (rate_int <= 1) {
8997 /* 0 is not allowed, some programs write 1 instead of the floating point
8999 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
9003 segment->rate = rate_int / 65536.0;
9006 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
9007 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
9008 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
9009 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
9010 i, GST_TIME_ARGS (segment->time),
9011 GST_TIME_ARGS (segment->duration),
9012 GST_TIME_ARGS (segment->media_start), media_time,
9013 GST_TIME_ARGS (segment->media_stop),
9014 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
9016 if (segment->stop_time > qtdemux->segment.stop) {
9017 GST_WARNING_OBJECT (qtdemux, "Segment %d "
9018 " extends to %" GST_TIME_FORMAT
9019 " past the end of the file duration %" GST_TIME_FORMAT
9020 " it will be truncated", i, GST_TIME_ARGS (segment->stop_time),
9021 GST_TIME_ARGS (qtdemux->segment.stop));
9022 qtdemux->segment.stop = segment->stop_time;
9025 buffer += entry_size;
9027 GST_DEBUG_OBJECT (qtdemux, "found %d segments", count);
9028 stream->n_segments = count;
9029 if (media_segments_count != 1)
9030 allow_pushbased_edts = FALSE;
9034 /* push based does not handle segments, so act accordingly here,
9035 * and warn if applicable */
9036 if (!qtdemux->pullbased && !allow_pushbased_edts) {
9037 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
9038 /* remove and use default one below, we stream like it anyway */
9039 g_free (stream->segments);
9040 stream->segments = NULL;
9041 stream->n_segments = 0;
9044 /* no segments, create one to play the complete trak */
9045 if (stream->n_segments == 0) {
9046 GstClockTime stream_duration =
9047 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
9049 if (stream->segments == NULL)
9050 stream->segments = g_new (QtDemuxSegment, 1);
9052 /* represent unknown our way */
9053 if (stream_duration == 0)
9054 stream_duration = GST_CLOCK_TIME_NONE;
9056 stream->segments[0].time = 0;
9057 stream->segments[0].stop_time = stream_duration;
9058 stream->segments[0].duration = stream_duration;
9059 stream->segments[0].media_start = 0;
9060 stream->segments[0].media_stop = stream_duration;
9061 stream->segments[0].rate = 1.0;
9062 stream->segments[0].trak_media_start = 0;
9064 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
9065 GST_TIME_ARGS (stream_duration));
9066 stream->n_segments = 1;
9067 stream->dummy_segment = TRUE;
9069 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
9075 * Parses the stsd atom of a svq3 trak looking for
9076 * the SMI and gama atoms.
9079 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
9080 const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
9082 const guint8 *_gamma = NULL;
9083 GstBuffer *_seqh = NULL;
9084 const guint8 *stsd_data = stsd_entry_data;
9085 guint32 length = QT_UINT32 (stsd_data);
9089 GST_WARNING_OBJECT (qtdemux, "stsd too short");
9095 version = QT_UINT16 (stsd_data);
9100 while (length > 8) {
9101 guint32 fourcc, size;
9103 size = QT_UINT32 (stsd_data);
9104 fourcc = QT_FOURCC (stsd_data + 4);
9105 data = stsd_data + 8;
9108 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
9109 "svq3 atom parsing");
9118 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
9119 " for gama atom, expected 12", size);
9124 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
9126 if (_seqh != NULL) {
9127 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
9128 " found, ignoring");
9130 seqh_size = QT_UINT32 (data + 4);
9131 if (seqh_size > 0) {
9132 _seqh = gst_buffer_new_and_alloc (seqh_size);
9133 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
9140 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
9141 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
9145 if (size <= length) {
9151 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
9154 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
9155 G_GUINT16_FORMAT, version);
9166 gst_buffer_unref (_seqh);
9171 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
9178 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
9179 * atom that might contain a 'data' atom with the rtsp uri.
9180 * This case was reported in bug #597497, some info about
9181 * the hndl atom can be found in TN1195
9183 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
9184 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
9187 guint32 dref_num_entries = 0;
9188 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
9189 gst_byte_reader_skip (&dref, 4) &&
9190 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
9193 /* search dref entries for hndl atom */
9194 for (i = 0; i < dref_num_entries; i++) {
9195 guint32 size = 0, type;
9196 guint8 string_len = 0;
9197 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
9198 qt_atom_parser_get_fourcc (&dref, &type)) {
9199 if (type == FOURCC_hndl) {
9200 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
9202 /* skip data reference handle bytes and the
9203 * following pascal string and some extra 4
9204 * bytes I have no idea what are */
9205 if (!gst_byte_reader_skip (&dref, 4) ||
9206 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
9207 !gst_byte_reader_skip (&dref, string_len + 4)) {
9208 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
9212 /* iterate over the atoms to find the data atom */
9213 while (gst_byte_reader_get_remaining (&dref) >= 8) {
9217 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
9218 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
9219 if (atom_type == FOURCC_data) {
9220 const guint8 *uri_aux = NULL;
9222 /* found the data atom that might contain the rtsp uri */
9223 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
9224 "hndl atom, interpreting it as an URI");
9225 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
9227 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
9228 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
9230 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
9231 "didn't contain a rtsp address");
9233 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
9238 /* skipping to the next entry */
9239 if (!gst_byte_reader_skip (&dref, atom_size - 8))
9242 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
9249 /* skip to the next entry */
9250 if (!gst_byte_reader_skip (&dref, size - 8))
9253 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
9256 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
9262 #define AMR_NB_ALL_MODES 0x81ff
9263 #define AMR_WB_ALL_MODES 0x83ff
9265 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
9267 /* The 'damr' atom is of the form:
9269 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
9270 * 32 b 8 b 16 b 8 b 8 b
9272 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
9273 * represents the highest mode used in the stream (and thus the maximum
9274 * bitrate), with a couple of special cases as seen below.
9277 /* Map of frame type ID -> bitrate */
9278 static const guint nb_bitrates[] = {
9279 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
9281 static const guint wb_bitrates[] = {
9282 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
9288 gst_buffer_map (buf, &map, GST_MAP_READ);
9290 if (map.size != 0x11) {
9291 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
9295 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
9296 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
9297 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
9301 mode_set = QT_UINT16 (map.data + 13);
9303 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
9304 max_mode = 7 + (wb ? 1 : 0);
9306 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
9307 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
9309 if (max_mode == -1) {
9310 GST_DEBUG ("No mode indication was found (mode set) = %x",
9315 gst_buffer_unmap (buf, &map);
9316 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
9319 gst_buffer_unmap (buf, &map);
9324 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
9325 GstByteReader * reader, guint32 * matrix, const gchar * atom)
9328 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
9334 if (gst_byte_reader_get_remaining (reader) < 36)
9337 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
9338 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
9339 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
9340 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
9341 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
9342 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
9343 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
9344 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
9345 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
9347 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
9348 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
9349 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
9351 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
9352 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
9354 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
9355 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
9362 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
9363 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
9370 * This macro will only compare value abdegh, it expects cfi to have already
9373 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
9374 (m)[3] == (d << 16) && (m)[4] == (e << 16))
9376 /* only handle the cases where the last column has standard values */
9377 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
9378 const gchar *rotation_tag = NULL;
9380 /* no rotation needed */
9381 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
9383 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
9384 rotation_tag = "rotate-90";
9385 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
9386 rotation_tag = "rotate-180";
9387 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
9388 rotation_tag = "rotate-270";
9390 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9393 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
9395 if (rotation_tag != NULL) {
9396 if (*taglist == NULL)
9397 *taglist = gst_tag_list_new_empty ();
9398 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
9399 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
9402 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9406 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
9407 * protected streams (sinf, frma, schm and schi); if the protection scheme is
9408 * Common Encryption (cenc), the function will also parse the tenc box (defined
9409 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
9410 * (typically an enc[v|a|t|s] sample entry); the function will set
9411 * @original_fmt to the fourcc of the original unencrypted stream format.
9412 * Returns TRUE if successful; FALSE otherwise. */
9414 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
9415 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
9422 g_return_val_if_fail (qtdemux != NULL, FALSE);
9423 g_return_val_if_fail (stream != NULL, FALSE);
9424 g_return_val_if_fail (container != NULL, FALSE);
9425 g_return_val_if_fail (original_fmt != NULL, FALSE);
9427 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
9428 if (G_UNLIKELY (!sinf)) {
9429 if (stream->protection_scheme_type == FOURCC_cenc) {
9430 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
9431 "mandatory for Common Encryption");
9437 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
9438 if (G_UNLIKELY (!frma)) {
9439 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
9443 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
9444 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
9445 GST_FOURCC_ARGS (*original_fmt));
9447 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
9449 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
9452 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
9453 stream->protection_scheme_version =
9454 QT_UINT32 ((const guint8 *) schm->data + 16);
9456 GST_DEBUG_OBJECT (qtdemux,
9457 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
9458 "protection_scheme_version: %#010x",
9459 GST_FOURCC_ARGS (stream->protection_scheme_type),
9460 stream->protection_scheme_version);
9462 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
9464 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
9467 if (stream->protection_scheme_type == FOURCC_cenc) {
9468 QtDemuxCencSampleSetInfo *info;
9470 const guint8 *tenc_data;
9471 guint32 isEncrypted;
9473 const guint8 *default_kid;
9476 if (G_UNLIKELY (!stream->protection_scheme_info))
9477 stream->protection_scheme_info =
9478 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
9480 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
9482 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
9484 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
9485 "which is mandatory for Common Encryption");
9488 tenc_data = (const guint8 *) tenc->data + 12;
9489 isEncrypted = QT_UINT24 (tenc_data);
9490 iv_size = QT_UINT8 (tenc_data + 3);
9491 default_kid = (tenc_data + 4);
9492 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
9493 gst_buffer_fill (kid_buf, 0, default_kid, 16);
9494 if (info->default_properties)
9495 gst_structure_free (info->default_properties);
9496 info->default_properties =
9497 gst_structure_new ("application/x-cenc",
9498 "iv_size", G_TYPE_UINT, iv_size,
9499 "encrypted", G_TYPE_BOOLEAN, (isEncrypted == 1),
9500 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
9501 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
9502 "is_encrypted=%u, iv_size=%u", isEncrypted, iv_size);
9503 gst_buffer_unref (kid_buf);
9509 * With each track we associate a new QtDemuxStream that contains all the info
9511 * traks that do not decode to something (like strm traks) will not have a pad.
9514 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
9535 QtDemuxStream *stream = NULL;
9536 gboolean new_stream = FALSE;
9537 gchar *codec = NULL;
9538 const guint8 *stsd_data;
9539 const guint8 *stsd_entry_data;
9540 guint remaining_stsd_len;
9541 guint stsd_entry_count;
9543 guint16 lang_code; /* quicktime lang code or packed iso code */
9545 guint32 tkhd_flags = 0;
9546 guint8 tkhd_version = 0;
9547 guint32 w = 0, h = 0;
9549 guint value_size, stsd_len, len;
9553 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
9555 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
9556 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
9557 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
9560 /* pick between 64 or 32 bits */
9561 value_size = tkhd_version == 1 ? 8 : 4;
9562 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
9563 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
9566 if (!qtdemux->got_moov) {
9567 if (qtdemux_find_stream (qtdemux, track_id))
9568 goto existing_stream;
9569 stream = _create_stream ();
9570 stream->track_id = track_id;
9573 stream = qtdemux_find_stream (qtdemux, track_id);
9575 GST_WARNING_OBJECT (qtdemux, "Stream not found, going to ignore it");
9579 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
9581 /* flush samples data from this track from previous moov */
9582 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
9583 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
9585 /* need defaults for fragments */
9586 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
9588 if ((tkhd_flags & 1) == 0)
9589 stream->disabled = TRUE;
9591 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
9592 tkhd_version, tkhd_flags, stream->track_id);
9594 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
9597 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
9598 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
9599 if (qtdemux->major_brand != FOURCC_mjp2 ||
9600 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
9604 len = QT_UINT32 ((guint8 *) mdhd->data);
9605 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
9606 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
9607 if (version == 0x01000000) {
9610 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
9611 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
9612 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
9616 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
9617 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
9618 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
9621 if (lang_code < 0x400) {
9622 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
9623 } else if (lang_code == 0x7fff) {
9624 stream->lang_id[0] = 0; /* unspecified */
9626 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
9627 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
9628 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
9629 stream->lang_id[3] = 0;
9632 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
9634 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
9636 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
9637 lang_code, stream->lang_id);
9639 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
9642 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
9643 /* chapters track reference */
9644 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
9646 gsize length = GST_READ_UINT32_BE (chap->data);
9647 if (qtdemux->chapters_track_id)
9648 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
9651 qtdemux->chapters_track_id =
9652 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
9657 /* fragmented files may have bogus duration in moov */
9658 if (!qtdemux->fragmented &&
9659 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
9660 guint64 tdur1, tdur2;
9662 /* don't overflow */
9663 tdur1 = stream->timescale * (guint64) qtdemux->duration;
9664 tdur2 = qtdemux->timescale * (guint64) stream->duration;
9667 * some of those trailers, nowadays, have prologue images that are
9668 * themselves video tracks as well. I haven't really found a way to
9669 * identify those yet, except for just looking at their duration. */
9670 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
9671 GST_WARNING_OBJECT (qtdemux,
9672 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
9673 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
9674 "found, assuming preview image or something; skipping track",
9675 stream->duration, stream->timescale, qtdemux->duration,
9676 qtdemux->timescale);
9678 gst_qtdemux_stream_free (qtdemux, stream);
9683 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
9686 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
9687 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
9689 len = QT_UINT32 ((guint8 *) hdlr->data);
9691 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
9692 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
9693 GST_FOURCC_ARGS (stream->subtype));
9695 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
9698 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
9701 /*parse svmi header if existing */
9702 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
9704 len = QT_UINT32 ((guint8 *) svmi->data);
9705 version = QT_UINT32 ((guint8 *) svmi->data + 8);
9707 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
9708 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
9709 guint8 frame_type, frame_layout;
9711 /* MPEG-A stereo video */
9712 if (qtdemux->major_brand == FOURCC_ss02)
9713 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
9715 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
9716 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
9717 switch (frame_type) {
9719 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
9722 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
9725 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
9728 /* mode 3 is primary/secondary view sequence, ie
9729 * left/right views in separate tracks. See section 7.2
9730 * of ISO/IEC 23000-11:2009 */
9731 GST_FIXME_OBJECT (qtdemux,
9732 "Implement stereo video in separate streams");
9735 if ((frame_layout & 0x1) == 0)
9736 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
9738 GST_LOG_OBJECT (qtdemux,
9739 "StereoVideo: composition type: %u, is_left_first: %u",
9740 frame_type, frame_layout);
9741 stream->multiview_mode = mode;
9742 stream->multiview_flags = flags;
9746 /* parse rest of tkhd */
9747 if (stream->subtype == FOURCC_vide) {
9750 /* version 1 uses some 64-bit ints */
9751 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
9754 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
9757 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
9758 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
9761 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
9762 &stream->stream_tags);
9766 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
9768 stsd_data = (const guint8 *) stsd->data;
9770 /* stsd should at least have one entry */
9771 stsd_len = QT_UINT32 (stsd_data);
9772 if (stsd_len < 24) {
9773 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
9774 if (stream->subtype == FOURCC_vivo) {
9776 gst_qtdemux_stream_free (qtdemux, stream);
9783 stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
9784 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
9785 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
9786 GST_LOG_OBJECT (qtdemux, "stsd entry count: %u", stsd_entry_count);
9788 stsd_entry_data = stsd_data + 16;
9789 remaining_stsd_len = stsd_len - 16;
9790 for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
9791 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
9793 /* and that entry should fit within stsd */
9794 len = QT_UINT32 (stsd_entry_data);
9795 if (len > remaining_stsd_len)
9798 entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
9799 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
9800 GST_FOURCC_ARGS (entry->fourcc));
9801 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
9803 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
9804 goto error_encrypted;
9806 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
9807 /* FIXME this looks wrong, there might be multiple children
9808 * with the same type */
9809 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
9810 stream->protected = TRUE;
9811 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
9812 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
9815 if (stream->subtype == FOURCC_vide) {
9817 gint depth, palette_size, palette_count;
9818 guint32 *palette_data = NULL;
9820 entry->sampled = TRUE;
9822 stream->display_width = w >> 16;
9823 stream->display_height = h >> 16;
9826 if (len < 86) /* TODO verify */
9829 entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
9830 entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
9831 entry->fps_n = 0; /* this is filled in later */
9832 entry->fps_d = 0; /* this is filled in later */
9833 entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
9834 entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
9836 /* if color_table_id is 0, ctab atom must follow; however some files
9837 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
9838 * if color table is not present we'll correct the value */
9839 if (entry->color_table_id == 0 &&
9841 || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
9842 entry->color_table_id = -1;
9845 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
9846 entry->width, entry->height, entry->bits_per_sample,
9847 entry->color_table_id);
9849 depth = entry->bits_per_sample;
9851 /* more than 32 bits means grayscale */
9852 gray = (depth > 32);
9853 /* low 32 bits specify the depth */
9856 /* different number of palette entries is determined by depth. */
9858 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
9859 palette_count = (1 << depth);
9860 palette_size = palette_count * 4;
9862 if (entry->color_table_id) {
9863 switch (palette_count) {
9867 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
9870 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
9875 g_memdup (ff_qt_grayscale_palette_16, palette_size);
9877 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
9882 g_memdup (ff_qt_grayscale_palette_256, palette_size);
9884 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
9887 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
9888 (_("The video in this file might not play correctly.")),
9889 ("unsupported palette depth %d", depth));
9893 gint i, j, start, end;
9899 start = QT_UINT32 (stsd_entry_data + offset + 70);
9900 palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
9901 end = QT_UINT16 (stsd_entry_data + offset + 76);
9903 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
9904 start, end, palette_count);
9911 if (len < 94 + (end - start) * 8)
9914 /* palette is always the same size */
9915 palette_data = g_malloc0 (256 * 4);
9916 palette_size = 256 * 4;
9918 for (j = 0, i = start; i <= end; j++, i++) {
9921 a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
9922 r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
9923 g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
9924 b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
9926 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
9927 (g & 0xff00) | (b >> 8);
9932 gst_caps_unref (entry->caps);
9935 qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
9937 if (G_UNLIKELY (!entry->caps)) {
9938 g_free (palette_data);
9939 goto unknown_stream;
9943 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
9944 GST_TAG_VIDEO_CODEC, codec, NULL);
9952 if (entry->rgb8_palette)
9953 gst_memory_unref (entry->rgb8_palette);
9954 entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
9955 palette_data, palette_size, 0, palette_size, palette_data, g_free);
9957 s = gst_caps_get_structure (entry->caps, 0);
9959 /* non-raw video has a palette_data property. raw video has the palette as
9960 * an extra plane that we append to the output buffers before we push
9962 if (!gst_structure_has_name (s, "video/x-raw")) {
9965 palette = gst_buffer_new ();
9966 gst_buffer_append_memory (palette, entry->rgb8_palette);
9967 entry->rgb8_palette = NULL;
9969 gst_caps_set_simple (entry->caps, "palette_data",
9970 GST_TYPE_BUFFER, palette, NULL);
9971 gst_buffer_unref (palette);
9973 } else if (palette_count != 0) {
9974 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
9975 (NULL), ("Unsupported palette depth %d", depth));
9978 GST_LOG_OBJECT (qtdemux, "frame count: %u",
9979 QT_UINT16 (stsd_entry_data + offset + 32));
9985 /* pick 'the' stsd child */
9986 mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
9987 if (!stream->protected) {
9988 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
9992 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) {
9998 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
9999 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
10000 colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
10001 fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
10005 const guint8 *pasp_data = (const guint8 *) pasp->data;
10006 gint len = QT_UINT32 (pasp_data);
10009 CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
10010 CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
10012 CUR_STREAM (stream)->par_w = 0;
10013 CUR_STREAM (stream)->par_h = 0;
10016 CUR_STREAM (stream)->par_w = 0;
10017 CUR_STREAM (stream)->par_h = 0;
10021 const guint8 *fiel_data = (const guint8 *) fiel->data;
10022 gint len = QT_UINT32 (fiel_data);
10025 CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
10026 CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
10031 const guint8 *colr_data = (const guint8 *) colr->data;
10032 gint len = QT_UINT32 (colr_data);
10034 if (len == 19 || len == 18) {
10035 guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
10037 if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
10038 guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
10039 guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
10040 guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
10041 gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
10043 switch (primaries) {
10045 CUR_STREAM (stream)->colorimetry.primaries =
10046 GST_VIDEO_COLOR_PRIMARIES_BT709;
10049 CUR_STREAM (stream)->colorimetry.primaries =
10050 GST_VIDEO_COLOR_PRIMARIES_BT470BG;
10053 CUR_STREAM (stream)->colorimetry.primaries =
10054 GST_VIDEO_COLOR_PRIMARIES_SMPTE170M;
10057 CUR_STREAM (stream)->colorimetry.primaries =
10058 GST_VIDEO_COLOR_PRIMARIES_BT2020;
10064 switch (transfer_function) {
10066 CUR_STREAM (stream)->colorimetry.transfer =
10067 GST_VIDEO_TRANSFER_BT709;
10070 CUR_STREAM (stream)->colorimetry.transfer =
10071 GST_VIDEO_TRANSFER_SMPTE240M;
10079 CUR_STREAM (stream)->colorimetry.matrix =
10080 GST_VIDEO_COLOR_MATRIX_BT709;
10083 CUR_STREAM (stream)->colorimetry.matrix =
10084 GST_VIDEO_COLOR_MATRIX_BT601;
10087 CUR_STREAM (stream)->colorimetry.matrix =
10088 GST_VIDEO_COLOR_MATRIX_SMPTE240M;
10091 CUR_STREAM (stream)->colorimetry.matrix =
10092 GST_VIDEO_COLOR_MATRIX_BT2020;
10098 CUR_STREAM (stream)->colorimetry.range =
10099 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
10100 GST_VIDEO_COLOR_RANGE_16_235;
10102 GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
10105 GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
10110 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
10111 stream->stream_tags);
10118 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10119 const guint8 *avc_data = stsd_entry_data + 0x56;
10122 while (len >= 0x8) {
10125 if (QT_UINT32 (avc_data) <= len)
10126 size = QT_UINT32 (avc_data) - 0x8;
10131 /* No real data, so break out */
10134 switch (QT_FOURCC (avc_data + 0x4)) {
10137 /* parse, if found */
10140 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
10142 /* First 4 bytes are the length of the atom, the next 4 bytes
10143 * are the fourcc, the next 1 byte is the version, and the
10144 * subsequent bytes are profile_tier_level structure like data. */
10145 gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
10146 avc_data + 8 + 1, size - 1);
10147 buf = gst_buffer_new_and_alloc (size);
10148 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
10149 gst_caps_set_simple (entry->caps,
10150 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10151 gst_buffer_unref (buf);
10159 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
10161 /* First 4 bytes are the length of the atom, the next 4 bytes
10162 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
10163 * next 1 byte is the version, and the
10164 * subsequent bytes are sequence parameter set like data. */
10166 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
10168 gst_codec_utils_h264_caps_set_level_and_profile
10169 (entry->caps, avc_data + 8 + 40 + 1, size - 1);
10171 buf = gst_buffer_new_and_alloc (size);
10172 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
10173 gst_caps_set_simple (entry->caps,
10174 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10175 gst_buffer_unref (buf);
10181 guint avg_bitrate, max_bitrate;
10183 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
10187 max_bitrate = QT_UINT32 (avc_data + 0xc);
10188 avg_bitrate = QT_UINT32 (avc_data + 0x10);
10190 if (!max_bitrate && !avg_bitrate)
10193 /* Some muxers seem to swap the average and maximum bitrates
10194 * (I'm looking at you, YouTube), so we swap for sanity. */
10195 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
10196 guint temp = avg_bitrate;
10198 avg_bitrate = max_bitrate;
10199 max_bitrate = temp;
10202 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
10203 gst_tag_list_add (stream->stream_tags,
10204 GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
10205 max_bitrate, NULL);
10207 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
10208 gst_tag_list_add (stream->stream_tags,
10209 GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
10221 avc_data += size + 8;
10230 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10231 const guint8 *hevc_data = stsd_entry_data + 0x56;
10234 while (len >= 0x8) {
10237 if (QT_UINT32 (hevc_data) <= len)
10238 size = QT_UINT32 (hevc_data) - 0x8;
10243 /* No real data, so break out */
10246 switch (QT_FOURCC (hevc_data + 0x4)) {
10249 /* parse, if found */
10252 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
10254 /* First 4 bytes are the length of the atom, the next 4 bytes
10255 * are the fourcc, the next 1 byte is the version, and the
10256 * subsequent bytes are sequence parameter set like data. */
10257 gst_codec_utils_h265_caps_set_level_tier_and_profile
10258 (entry->caps, hevc_data + 8 + 1, size - 1);
10260 buf = gst_buffer_new_and_alloc (size);
10261 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
10262 gst_caps_set_simple (entry->caps,
10263 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10264 gst_buffer_unref (buf);
10271 hevc_data += size + 8;
10284 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
10285 GST_FOURCC_ARGS (fourcc));
10287 /* codec data might be in glbl extension atom */
10289 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
10295 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
10297 len = QT_UINT32 (data);
10300 buf = gst_buffer_new_and_alloc (len);
10301 gst_buffer_fill (buf, 0, data + 8, len);
10302 gst_caps_set_simple (entry->caps,
10303 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10304 gst_buffer_unref (buf);
10311 /* see annex I of the jpeg2000 spec */
10312 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
10313 const guint8 *data;
10314 const gchar *colorspace = NULL;
10316 guint32 ncomp_map = 0;
10317 gint32 *comp_map = NULL;
10318 guint32 nchan_def = 0;
10319 gint32 *chan_def = NULL;
10321 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
10322 /* some required atoms */
10323 mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10326 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
10330 /* number of components; redundant with info in codestream, but useful
10332 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
10333 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
10335 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
10337 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
10340 GST_DEBUG_OBJECT (qtdemux, "found colr");
10341 /* extract colour space info */
10342 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
10343 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
10345 colorspace = "sRGB";
10348 colorspace = "GRAY";
10351 colorspace = "sYUV";
10359 /* colr is required, and only values 16, 17, and 18 are specified,
10360 so error if we have no colorspace */
10363 /* extract component mapping */
10364 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
10366 guint32 cmap_len = 0;
10368 cmap_len = QT_UINT32 (cmap->data);
10369 if (cmap_len >= 8) {
10370 /* normal box, subtract off header */
10372 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
10373 if (cmap_len % 4 == 0) {
10374 ncomp_map = (cmap_len / 4);
10375 comp_map = g_new0 (gint32, ncomp_map);
10376 for (i = 0; i < ncomp_map; i++) {
10379 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
10380 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
10381 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
10382 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
10387 /* extract channel definitions */
10388 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
10390 guint32 cdef_len = 0;
10392 cdef_len = QT_UINT32 (cdef->data);
10393 if (cdef_len >= 10) {
10394 /* normal box, subtract off header and len */
10396 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
10397 if (cdef_len % 6 == 0) {
10398 nchan_def = (cdef_len / 6);
10399 chan_def = g_new0 (gint32, nchan_def);
10400 for (i = 0; i < nchan_def; i++)
10402 for (i = 0; i < nchan_def; i++) {
10403 guint16 cn, typ, asoc;
10404 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
10405 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
10406 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
10407 if (cn < nchan_def) {
10410 chan_def[cn] = asoc;
10413 chan_def[cn] = 0; /* alpha */
10416 chan_def[cn] = -typ;
10424 gst_caps_set_simple (entry->caps,
10425 "num-components", G_TYPE_INT, ncomp, NULL);
10426 gst_caps_set_simple (entry->caps,
10427 "colorspace", G_TYPE_STRING, colorspace, NULL);
10430 GValue arr = { 0, };
10431 GValue elt = { 0, };
10433 g_value_init (&arr, GST_TYPE_ARRAY);
10434 g_value_init (&elt, G_TYPE_INT);
10435 for (i = 0; i < ncomp_map; i++) {
10436 g_value_set_int (&elt, comp_map[i]);
10437 gst_value_array_append_value (&arr, &elt);
10439 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
10440 "component-map", &arr);
10441 g_value_unset (&elt);
10442 g_value_unset (&arr);
10447 GValue arr = { 0, };
10448 GValue elt = { 0, };
10450 g_value_init (&arr, GST_TYPE_ARRAY);
10451 g_value_init (&elt, G_TYPE_INT);
10452 for (i = 0; i < nchan_def; i++) {
10453 g_value_set_int (&elt, chan_def[i]);
10454 gst_value_array_append_value (&arr, &elt);
10456 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
10457 "channel-definitions", &arr);
10458 g_value_unset (&elt);
10459 g_value_unset (&arr);
10463 /* some optional atoms */
10464 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
10465 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
10467 /* indicate possible fields in caps */
10469 data = (guint8 *) field->data + 8;
10471 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
10472 (gint) * data, NULL);
10474 /* add codec_data if provided */
10479 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
10480 data = prefix->data;
10481 len = QT_UINT32 (data);
10484 buf = gst_buffer_new_and_alloc (len);
10485 gst_buffer_fill (buf, 0, data + 8, len);
10486 gst_caps_set_simple (entry->caps,
10487 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10488 gst_buffer_unref (buf);
10497 GstBuffer *seqh = NULL;
10498 const guint8 *gamma_data = NULL;
10499 gint len = QT_UINT32 (stsd_data); /* FIXME review - why put the whole stsd in codec data? */
10501 qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
10504 gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
10505 QT_FP32 (gamma_data), NULL);
10508 /* sorry for the bad name, but we don't know what this is, other
10509 * than its own fourcc */
10510 gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
10512 gst_buffer_unref (seqh);
10515 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
10516 buf = gst_buffer_new_and_alloc (len);
10517 gst_buffer_fill (buf, 0, stsd_data, len);
10518 gst_caps_set_simple (entry->caps,
10519 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10520 gst_buffer_unref (buf);
10525 /* https://developer.apple.com/standards/qtff-2001.pdf,
10526 * page 92, "Video Sample Description", under table 3.1 */
10529 const gint compressor_offset =
10530 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
10531 const gint min_size = compressor_offset + 32 + 2 + 2;
10534 guint16 color_table_id = 0;
10537 GST_DEBUG_OBJECT (qtdemux, "found jpeg");
10539 /* recover information on interlaced/progressive */
10540 jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
10544 len = QT_UINT32 (jpeg->data);
10545 GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
10547 if (len >= min_size) {
10548 gst_byte_reader_init (&br, jpeg->data, len);
10550 gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
10551 gst_byte_reader_get_uint16_le (&br, &color_table_id);
10552 if (color_table_id != 0) {
10553 /* the spec says there can be concatenated chunks in the data, and we want
10554 * to find one called field. Walk through them. */
10555 gint offset = min_size;
10556 while (offset + 8 < len) {
10557 guint32 size = 0, tag;
10558 ok = gst_byte_reader_get_uint32_le (&br, &size);
10559 ok &= gst_byte_reader_get_uint32_le (&br, &tag);
10560 if (!ok || size < 8) {
10561 GST_WARNING_OBJECT (qtdemux,
10562 "Failed to walk optional chunk list");
10565 GST_DEBUG_OBJECT (qtdemux,
10566 "Found optional %4.4s chunk, size %u",
10567 (const char *) &tag, size);
10568 if (tag == FOURCC_fiel) {
10569 guint8 n_fields = 0, ordering = 0;
10570 gst_byte_reader_get_uint8 (&br, &n_fields);
10571 gst_byte_reader_get_uint8 (&br, &ordering);
10572 if (n_fields == 1 || n_fields == 2) {
10573 GST_DEBUG_OBJECT (qtdemux,
10574 "Found fiel tag with %u fields, ordering %u",
10575 n_fields, ordering);
10577 gst_caps_set_simple (CUR_STREAM (stream)->caps,
10578 "interlace-mode", G_TYPE_STRING, "interleaved",
10581 GST_WARNING_OBJECT (qtdemux,
10582 "Found fiel tag with invalid fields (%u)", n_fields);
10588 GST_DEBUG_OBJECT (qtdemux,
10589 "Color table ID is 0, not trying to get interlacedness");
10592 GST_WARNING_OBJECT (qtdemux,
10593 "Length of jpeg chunk is too small, not trying to get interlacedness");
10601 gst_caps_set_simple (entry->caps,
10602 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 82),
10608 GNode *xith, *xdxt;
10610 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
10611 xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10615 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
10619 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
10620 /* collect the headers and store them in a stream list so that we can
10621 * send them out first */
10622 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
10632 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
10633 ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10636 ovc1_data = ovc1->data;
10637 ovc1_len = QT_UINT32 (ovc1_data);
10638 if (ovc1_len <= 198) {
10639 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
10642 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
10643 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
10644 gst_caps_set_simple (entry->caps,
10645 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10646 gst_buffer_unref (buf);
10651 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10652 const guint8 *vc1_data = stsd_entry_data + 0x56;
10658 if (QT_UINT32 (vc1_data) <= len)
10659 size = QT_UINT32 (vc1_data) - 8;
10664 /* No real data, so break out */
10667 switch (QT_FOURCC (vc1_data + 0x4)) {
10668 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
10672 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
10673 buf = gst_buffer_new_and_alloc (size);
10674 gst_buffer_fill (buf, 0, vc1_data + 8, size);
10675 gst_caps_set_simple (entry->caps,
10676 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10677 gst_buffer_unref (buf);
10684 vc1_data += size + 8;
10693 GST_INFO_OBJECT (qtdemux,
10694 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10695 GST_FOURCC_ARGS (fourcc), entry->caps);
10697 } else if (stream->subtype == FOURCC_soun) {
10698 int version, samplesize;
10699 guint16 compression_id;
10700 gboolean amrwb = FALSE;
10703 /* sample description entry (16) + sound sample description v0 (20) */
10707 version = QT_UINT32 (stsd_entry_data + offset);
10708 entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
10709 samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
10710 compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
10711 entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
10713 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
10714 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
10715 QT_UINT32 (stsd_entry_data + offset + 4));
10716 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
10717 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
10718 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
10719 GST_LOG_OBJECT (qtdemux, "packet size: %d",
10720 QT_UINT16 (stsd_entry_data + offset + 14));
10721 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
10723 if (compression_id == 0xfffe)
10724 entry->sampled = TRUE;
10726 /* first assume uncompressed audio */
10727 entry->bytes_per_sample = samplesize / 8;
10728 entry->samples_per_frame = entry->n_channels;
10729 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
10730 entry->samples_per_packet = entry->samples_per_frame;
10731 entry->bytes_per_packet = entry->bytes_per_sample;
10735 /* Yes, these have to be hard-coded */
10738 entry->samples_per_packet = 6;
10739 entry->bytes_per_packet = 1;
10740 entry->bytes_per_frame = 1 * entry->n_channels;
10741 entry->bytes_per_sample = 1;
10742 entry->samples_per_frame = 6 * entry->n_channels;
10747 entry->samples_per_packet = 3;
10748 entry->bytes_per_packet = 1;
10749 entry->bytes_per_frame = 1 * entry->n_channels;
10750 entry->bytes_per_sample = 1;
10751 entry->samples_per_frame = 3 * entry->n_channels;
10756 entry->samples_per_packet = 64;
10757 entry->bytes_per_packet = 34;
10758 entry->bytes_per_frame = 34 * entry->n_channels;
10759 entry->bytes_per_sample = 2;
10760 entry->samples_per_frame = 64 * entry->n_channels;
10766 entry->samples_per_packet = 1;
10767 entry->bytes_per_packet = 1;
10768 entry->bytes_per_frame = 1 * entry->n_channels;
10769 entry->bytes_per_sample = 1;
10770 entry->samples_per_frame = 1 * entry->n_channels;
10775 entry->samples_per_packet = 160;
10776 entry->bytes_per_packet = 33;
10777 entry->bytes_per_frame = 33 * entry->n_channels;
10778 entry->bytes_per_sample = 2;
10779 entry->samples_per_frame = 160 * entry->n_channels;
10786 if (version == 0x00010000) {
10787 /* sample description entry (16) + sound sample description v1 (20+16) */
10798 /* only parse extra decoding config for non-pcm audio */
10799 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
10800 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
10801 entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
10802 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
10804 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
10805 entry->samples_per_packet);
10806 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
10807 entry->bytes_per_packet);
10808 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
10809 entry->bytes_per_frame);
10810 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
10811 entry->bytes_per_sample);
10813 if (!entry->sampled && entry->bytes_per_packet) {
10814 entry->samples_per_frame = (entry->bytes_per_frame /
10815 entry->bytes_per_packet) * entry->samples_per_packet;
10816 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
10817 entry->samples_per_frame);
10822 } else if (version == 0x00020000) {
10829 /* sample description entry (16) + sound sample description v2 (56) */
10833 qtfp.val = QT_UINT64 (stsd_entry_data + offset + 4);
10834 entry->rate = qtfp.fp;
10835 entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
10837 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
10838 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
10839 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
10840 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
10841 QT_UINT32 (stsd_entry_data + offset + 20));
10842 GST_LOG_OBJECT (qtdemux, "format flags: %X",
10843 QT_UINT32 (stsd_entry_data + offset + 24));
10844 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
10845 QT_UINT32 (stsd_entry_data + offset + 28));
10846 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
10847 QT_UINT32 (stsd_entry_data + offset + 32));
10848 } else if (version != 0x00000) {
10849 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
10854 gst_caps_unref (entry->caps);
10856 entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
10857 stsd_entry_data + 32, len - 16, &codec);
10865 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
10867 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
10869 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
10871 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
10874 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
10875 gst_caps_set_simple (entry->caps,
10876 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE",
10883 const guint8 *owma_data;
10884 const gchar *codec_name = NULL;
10888 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
10889 /* FIXME this should also be gst_riff_strf_auds,
10890 * but the latter one is actually missing bits-per-sample :( */
10895 gint32 nSamplesPerSec;
10896 gint32 nAvgBytesPerSec;
10897 gint16 nBlockAlign;
10898 gint16 wBitsPerSample;
10901 WAVEFORMATEX *wfex;
10903 GST_DEBUG_OBJECT (qtdemux, "parse owma");
10904 owma_data = stsd_entry_data;
10905 owma_len = QT_UINT32 (owma_data);
10906 if (owma_len <= 54) {
10907 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
10910 wfex = (WAVEFORMATEX *) (owma_data + 36);
10911 buf = gst_buffer_new_and_alloc (owma_len - 54);
10912 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
10913 if (wfex->wFormatTag == 0x0161) {
10914 codec_name = "Windows Media Audio";
10916 } else if (wfex->wFormatTag == 0x0162) {
10917 codec_name = "Windows Media Audio 9 Pro";
10919 } else if (wfex->wFormatTag == 0x0163) {
10920 codec_name = "Windows Media Audio 9 Lossless";
10921 /* is that correct? gstffmpegcodecmap.c is missing it, but
10922 * fluendo codec seems to support it */
10926 gst_caps_set_simple (entry->caps,
10927 "codec_data", GST_TYPE_BUFFER, buf,
10928 "wmaversion", G_TYPE_INT, version,
10929 "block_align", G_TYPE_INT,
10930 GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
10931 GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
10932 GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
10933 GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
10934 gst_buffer_unref (buf);
10938 codec = g_strdup (codec_name);
10944 gint len = QT_UINT32 (stsd_entry_data) - offset;
10945 const guint8 *wfex_data = stsd_entry_data + offset;
10946 const gchar *codec_name = NULL;
10948 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
10949 /* FIXME this should also be gst_riff_strf_auds,
10950 * but the latter one is actually missing bits-per-sample :( */
10955 gint32 nSamplesPerSec;
10956 gint32 nAvgBytesPerSec;
10957 gint16 nBlockAlign;
10958 gint16 wBitsPerSample;
10963 /* FIXME: unify with similar wavformatex parsing code above */
10964 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
10970 if (QT_UINT32 (wfex_data) <= len)
10971 size = QT_UINT32 (wfex_data) - 8;
10976 /* No real data, so break out */
10979 switch (QT_FOURCC (wfex_data + 4)) {
10980 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
10982 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
10987 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
10988 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
10989 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
10990 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
10991 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
10992 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
10993 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
10995 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
10996 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
10997 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
10998 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
10999 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
11000 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
11002 if (wfex.wFormatTag == 0x0161) {
11003 codec_name = "Windows Media Audio";
11005 } else if (wfex.wFormatTag == 0x0162) {
11006 codec_name = "Windows Media Audio 9 Pro";
11008 } else if (wfex.wFormatTag == 0x0163) {
11009 codec_name = "Windows Media Audio 9 Lossless";
11010 /* is that correct? gstffmpegcodecmap.c is missing it, but
11011 * fluendo codec seems to support it */
11015 gst_caps_set_simple (entry->caps,
11016 "wmaversion", G_TYPE_INT, version,
11017 "block_align", G_TYPE_INT, wfex.nBlockAlign,
11018 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
11019 "width", G_TYPE_INT, wfex.wBitsPerSample,
11020 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
11022 if (size > wfex.cbSize) {
11025 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
11026 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
11027 size - wfex.cbSize);
11028 gst_caps_set_simple (entry->caps,
11029 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11030 gst_buffer_unref (buf);
11032 GST_WARNING_OBJECT (qtdemux, "no codec data");
11037 codec = g_strdup (codec_name);
11045 wfex_data += size + 8;
11051 const guint8 *opus_data;
11052 guint8 *channel_mapping = NULL;
11055 guint8 channel_mapping_family;
11056 guint8 stream_count;
11057 guint8 coupled_count;
11060 opus_data = stsd_entry_data;
11062 channels = GST_READ_UINT8 (opus_data + 45);
11063 rate = GST_READ_UINT32_LE (opus_data + 48);
11064 channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
11065 stream_count = GST_READ_UINT8 (opus_data + 55);
11066 coupled_count = GST_READ_UINT8 (opus_data + 56);
11068 if (channels > 0) {
11069 channel_mapping = g_malloc (channels * sizeof (guint8));
11070 for (i = 0; i < channels; i++)
11071 channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
11074 entry->caps = gst_codec_utils_opus_create_caps (rate, channels,
11075 channel_mapping_family, stream_count, coupled_count,
11087 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11088 GST_TAG_AUDIO_CODEC, codec, NULL);
11092 /* some bitrate info may have ended up in caps */
11093 s = gst_caps_get_structure (entry->caps, 0);
11094 gst_structure_get_int (s, "bitrate", &bitrate);
11096 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11097 GST_TAG_BITRATE, bitrate, NULL);
11100 mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11101 if (!stream->protected) {
11103 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) {
11107 if (stream->protected && fourcc == FOURCC_mp4a) {
11108 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) {
11112 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_mp4a) {
11120 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
11122 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
11124 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
11128 /* If the fourcc's bottom 16 bits gives 'sm', then the top
11129 16 bits is a byte-swapped wave-style codec identifier,
11130 and we can find a WAVE header internally to a 'wave' atom here.
11131 This can more clearly be thought of as 'ms' as the top 16 bits, and a
11132 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
11135 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
11136 if (len < offset + 20) {
11137 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
11139 guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
11140 const guint8 *data = stsd_entry_data + offset + 16;
11142 GNode *waveheadernode;
11144 wavenode = g_node_new ((guint8 *) data);
11145 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
11146 const guint8 *waveheader;
11149 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
11150 if (waveheadernode) {
11151 waveheader = (const guint8 *) waveheadernode->data;
11152 headerlen = QT_UINT32 (waveheader);
11154 if (headerlen > 8) {
11155 gst_riff_strf_auds *header = NULL;
11156 GstBuffer *headerbuf;
11162 headerbuf = gst_buffer_new_and_alloc (headerlen);
11163 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
11165 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
11166 headerbuf, &header, &extra)) {
11167 gst_caps_unref (entry->caps);
11168 /* FIXME: Need to do something with the channel reorder map */
11170 gst_riff_create_audio_caps (header->format, NULL, header,
11171 extra, NULL, NULL, NULL);
11174 gst_buffer_unref (extra);
11179 GST_DEBUG ("Didn't find waveheadernode for this codec");
11181 g_node_destroy (wavenode);
11184 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11185 stream->stream_tags);
11189 /* FIXME: what is in the chunk? */
11192 gint len = QT_UINT32 (stsd_data);
11194 /* seems to be always = 116 = 0x74 */
11200 gint len = QT_UINT32 (stsd_entry_data);
11203 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
11205 gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
11206 gst_caps_set_simple (entry->caps,
11207 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11208 gst_buffer_unref (buf);
11210 gst_caps_set_simple (entry->caps,
11211 "samplesize", G_TYPE_INT, samplesize, NULL);
11216 GNode *alac, *wave = NULL;
11218 /* apparently, m4a has this atom appended directly in the stsd entry,
11219 * while mov has it in a wave atom */
11220 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
11222 /* alac now refers to stsd entry atom */
11223 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
11225 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
11227 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
11230 const guint8 *alac_data = alac->data;
11231 gint len = QT_UINT32 (alac->data);
11235 GST_DEBUG_OBJECT (qtdemux,
11236 "discarding alac atom with unexpected len %d", len);
11238 /* codec-data contains alac atom size and prefix,
11239 * ffmpeg likes it that way, not quite gst-ish though ...*/
11240 buf = gst_buffer_new_and_alloc (len);
11241 gst_buffer_fill (buf, 0, alac->data, len);
11242 gst_caps_set_simple (entry->caps,
11243 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11244 gst_buffer_unref (buf);
11246 entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
11247 entry->n_channels = QT_UINT8 (alac_data + 21);
11248 entry->rate = QT_UINT32 (alac_data + 32);
11251 gst_caps_set_simple (entry->caps,
11252 "samplesize", G_TYPE_INT, samplesize, NULL);
11257 /* The codingname of the sample entry is 'fLaC' */
11258 GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
11261 /* The 'dfLa' box is added to the sample entry to convey
11262 initializing information for the decoder. */
11263 const GNode *dfla =
11264 qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
11267 const guint32 len = QT_UINT32 (dfla->data);
11269 /* Must contain at least dfLa box header (12),
11270 * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
11272 GST_DEBUG_OBJECT (qtdemux,
11273 "discarding dfla atom with unexpected len %d", len);
11275 /* skip dfLa header to get the METADATA_BLOCKs */
11276 const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
11277 const guint32 metadata_blocks_len = len - 12;
11279 gchar *stream_marker = g_strdup ("fLaC");
11280 GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
11281 strlen (stream_marker));
11284 guint32 remainder = 0;
11285 guint32 block_size = 0;
11286 gboolean is_last = FALSE;
11288 GValue array = G_VALUE_INIT;
11289 GValue value = G_VALUE_INIT;
11291 g_value_init (&array, GST_TYPE_ARRAY);
11292 g_value_init (&value, GST_TYPE_BUFFER);
11294 gst_value_set_buffer (&value, block);
11295 gst_value_array_append_value (&array, &value);
11296 g_value_reset (&value);
11298 gst_buffer_unref (block);
11300 /* check there's at least one METADATA_BLOCK_HEADER's worth
11301 * of data, and we haven't already finished parsing */
11302 while (!is_last && ((index + 3) < metadata_blocks_len)) {
11303 remainder = metadata_blocks_len - index;
11305 /* add the METADATA_BLOCK_HEADER size to the signalled size */
11307 (metadata_blocks[index + 1] << 16) +
11308 (metadata_blocks[index + 2] << 8) +
11309 metadata_blocks[index + 3];
11311 /* be careful not to read off end of box */
11312 if (block_size > remainder) {
11316 is_last = metadata_blocks[index] >> 7;
11318 block = gst_buffer_new_and_alloc (block_size);
11320 gst_buffer_fill (block, 0, &metadata_blocks[index],
11323 gst_value_set_buffer (&value, block);
11324 gst_value_array_append_value (&array, &value);
11325 g_value_reset (&value);
11327 gst_buffer_unref (block);
11329 index += block_size;
11332 /* only append the metadata if we successfully read all of it */
11334 gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
11335 (stream)->caps, 0), "streamheader", &array);
11337 GST_WARNING_OBJECT (qtdemux,
11338 "discarding all METADATA_BLOCKs due to invalid "
11339 "block_size %d at idx %d, rem %d", block_size, index,
11343 g_value_unset (&value);
11344 g_value_unset (&array);
11346 /* The sample rate obtained from the stsd may not be accurate
11347 * since it cannot represent rates greater than 65535Hz, so
11348 * override that value with the sample rate from the
11349 * METADATA_BLOCK_STREAMINFO block */
11350 CUR_STREAM (stream)->rate =
11351 (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
11362 gint len = QT_UINT32 (stsd_entry_data);
11365 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
11368 gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
11370 /* If we have enough data, let's try to get the 'damr' atom. See
11371 * the 3GPP container spec (26.244) for more details. */
11372 if ((len - 0x34) > 8 &&
11373 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
11374 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11375 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
11378 gst_caps_set_simple (entry->caps,
11379 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11380 gst_buffer_unref (buf);
11386 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
11387 gint len = QT_UINT32 (stsd_entry_data);
11390 guint16 sound_version = QT_UINT16 (stsd_entry_data + 16);
11392 if (sound_version == 1) {
11393 guint16 channels = QT_UINT16 (stsd_entry_data + 24);
11394 guint32 time_scale = QT_UINT32 (stsd_entry_data + 30);
11395 guint8 codec_data[2];
11397 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
11399 gint sample_rate_index =
11400 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
11402 /* build AAC codec data */
11403 codec_data[0] = profile << 3;
11404 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
11405 codec_data[1] = (sample_rate_index & 0x01) << 7;
11406 codec_data[1] |= (channels & 0xF) << 3;
11408 buf = gst_buffer_new_and_alloc (2);
11409 gst_buffer_fill (buf, 0, codec_data, 2);
11410 gst_caps_set_simple (entry->caps,
11411 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11412 gst_buffer_unref (buf);
11418 GST_INFO_OBJECT (qtdemux,
11419 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11423 GST_INFO_OBJECT (qtdemux,
11424 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11425 GST_FOURCC_ARGS (fourcc), entry->caps);
11427 } else if (stream->subtype == FOURCC_strm) {
11428 if (fourcc == FOURCC_rtsp) {
11429 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
11431 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
11432 GST_FOURCC_ARGS (fourcc));
11433 goto unknown_stream;
11435 entry->sampled = TRUE;
11436 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
11437 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
11439 entry->sampled = TRUE;
11440 entry->sparse = TRUE;
11443 qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11446 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11447 GST_TAG_SUBTITLE_CODEC, codec, NULL);
11452 /* hunt for sort-of codec data */
11456 GNode *mp4s = NULL;
11457 GNode *esds = NULL;
11459 /* look for palette in a stsd->mp4s->esds sub-atom */
11460 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
11462 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
11463 if (esds == NULL) {
11465 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
11469 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11470 stream->stream_tags);
11474 GST_INFO_OBJECT (qtdemux,
11475 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11478 GST_INFO_OBJECT (qtdemux,
11479 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11480 GST_FOURCC_ARGS (fourcc), entry->caps);
11482 /* everything in 1 sample */
11483 entry->sampled = TRUE;
11486 qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11489 if (entry->caps == NULL)
11490 goto unknown_stream;
11493 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11494 GST_TAG_SUBTITLE_CODEC, codec, NULL);
11500 /* promote to sampled format */
11501 if (entry->fourcc == FOURCC_samr) {
11502 /* force mono 8000 Hz for AMR */
11503 entry->sampled = TRUE;
11504 entry->n_channels = 1;
11505 entry->rate = 8000;
11506 } else if (entry->fourcc == FOURCC_sawb) {
11507 /* force mono 16000 Hz for AMR-WB */
11508 entry->sampled = TRUE;
11509 entry->n_channels = 1;
11510 entry->rate = 16000;
11511 } else if (entry->fourcc == FOURCC_mp4a) {
11512 entry->sampled = TRUE;
11516 stsd_entry_data += len;
11517 remaining_stsd_len -= len;
11521 /* collect sample information */
11522 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
11523 goto samples_failed;
11525 if (qtdemux->fragmented) {
11528 /* need all moov samples as basis; probably not many if any at all */
11529 /* prevent moof parsing taking of at this time */
11530 offset = qtdemux->moof_offset;
11531 qtdemux->moof_offset = 0;
11532 if (stream->n_samples &&
11533 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
11534 qtdemux->moof_offset = offset;
11535 goto samples_failed;
11537 qtdemux->moof_offset = 0;
11538 /* movie duration more reliable in this case (e.g. mehd) */
11539 if (qtdemux->segment.duration &&
11540 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
11542 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
11545 /* configure segments */
11546 if (!qtdemux_parse_segments (qtdemux, stream, trak))
11547 goto segments_failed;
11549 /* add some language tag, if useful */
11550 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
11551 strcmp (stream->lang_id, "und")) {
11552 const gchar *lang_code;
11554 /* convert ISO 639-2 code to ISO 639-1 */
11555 lang_code = gst_tag_get_language_code (stream->lang_id);
11556 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11557 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
11560 /* Check for UDTA tags */
11561 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
11562 qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
11565 /* now we are ready to add the stream */
11566 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
11567 goto too_many_streams;
11569 if (!qtdemux->got_moov) {
11570 qtdemux->streams[qtdemux->n_streams] = stream;
11571 qtdemux->n_streams++;
11572 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
11580 GST_INFO_OBJECT (qtdemux, "skip disabled track");
11582 gst_qtdemux_stream_free (qtdemux, stream);
11587 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
11588 (_("This file is corrupt and cannot be played.")), (NULL));
11590 gst_qtdemux_stream_free (qtdemux, stream);
11595 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
11597 gst_qtdemux_stream_free (qtdemux, stream);
11603 /* we posted an error already */
11604 /* free stbl sub-atoms */
11605 gst_qtdemux_stbl_free (stream);
11607 gst_qtdemux_stream_free (qtdemux, stream);
11612 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
11615 gst_qtdemux_stream_free (qtdemux, stream);
11620 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
11621 GST_FOURCC_ARGS (stream->subtype));
11623 gst_qtdemux_stream_free (qtdemux, stream);
11628 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
11629 (_("This file contains too many streams. Only playing first %d"),
11630 GST_QTDEMUX_MAX_STREAMS), (NULL));
11635 /* If we can estimate the overall bitrate, and don't have information about the
11636 * stream bitrate for exactly one stream, this guesses the stream bitrate as
11637 * the overall bitrate minus the sum of the bitrates of all other streams. This
11638 * should be useful for the common case where we have one audio and one video
11639 * stream and can estimate the bitrate of one, but not the other. */
11641 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
11643 QtDemuxStream *stream = NULL;
11644 gint64 size, sys_bitrate, sum_bitrate = 0;
11645 GstClockTime duration;
11649 if (qtdemux->fragmented)
11652 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
11654 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
11656 GST_DEBUG_OBJECT (qtdemux,
11657 "Size in bytes of the stream not known - bailing");
11661 /* Subtract the header size */
11662 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
11663 size, qtdemux->header_size);
11665 if (size < qtdemux->header_size)
11668 size = size - qtdemux->header_size;
11670 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
11671 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
11675 for (i = 0; i < qtdemux->n_streams; i++) {
11676 switch (qtdemux->streams[i]->subtype) {
11679 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
11680 CUR_STREAM (qtdemux->streams[i])->caps);
11681 /* retrieve bitrate, prefer avg then max */
11683 if (qtdemux->streams[i]->stream_tags) {
11684 gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags,
11685 GST_TAG_MAXIMUM_BITRATE, &bitrate);
11686 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
11687 gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags,
11688 GST_TAG_NOMINAL_BITRATE, &bitrate);
11689 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
11690 gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags,
11691 GST_TAG_BITRATE, &bitrate);
11692 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
11695 sum_bitrate += bitrate;
11698 GST_DEBUG_OBJECT (qtdemux,
11699 ">1 stream with unknown bitrate - bailing");
11702 stream = qtdemux->streams[i];
11706 /* For other subtypes, we assume no significant impact on bitrate */
11712 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
11716 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
11718 if (sys_bitrate < sum_bitrate) {
11719 /* This can happen, since sum_bitrate might be derived from maximum
11720 * bitrates and not average bitrates */
11721 GST_DEBUG_OBJECT (qtdemux,
11722 "System bitrate less than sum bitrate - bailing");
11726 bitrate = sys_bitrate - sum_bitrate;
11727 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
11728 ", Stream bitrate = %u", sys_bitrate, bitrate);
11730 if (!stream->stream_tags)
11731 stream->stream_tags = gst_tag_list_new_empty ();
11733 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
11735 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11736 GST_TAG_BITRATE, bitrate, NULL);
11739 static GstFlowReturn
11740 qtdemux_prepare_streams (GstQTDemux * qtdemux)
11743 GstFlowReturn ret = GST_FLOW_OK;
11745 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
11747 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
11748 QtDemuxStream *stream = qtdemux->streams[i];
11749 guint32 sample_num = 0;
11751 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
11752 i, stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
11754 if (qtdemux->fragmented) {
11755 /* need all moov samples first */
11756 GST_OBJECT_LOCK (qtdemux);
11757 while (stream->n_samples == 0)
11758 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
11760 GST_OBJECT_UNLOCK (qtdemux);
11762 /* discard any stray moof */
11763 qtdemux->moof_offset = 0;
11766 /* prepare braking */
11767 if (ret != GST_FLOW_ERROR)
11770 /* in pull mode, we should have parsed some sample info by now;
11771 * and quite some code will not handle no samples.
11772 * in push mode, we'll just have to deal with it */
11773 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
11774 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
11775 gst_qtdemux_remove_stream (qtdemux, i);
11780 /* parse the initial sample for use in setting the frame rate cap */
11781 while (sample_num == 0 && sample_num < stream->n_samples) {
11782 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
11786 if (stream->n_samples > 0 && stream->stbl_index >= 0) {
11787 stream->first_duration = stream->samples[0].duration;
11788 GST_LOG_OBJECT (qtdemux, "stream %d first duration %u",
11789 stream->track_id, stream->first_duration);
11796 static GstFlowReturn
11797 qtdemux_expose_streams (GstQTDemux * qtdemux)
11800 GSList *oldpads = NULL;
11803 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
11805 for (i = 0; i < qtdemux->n_streams; i++) {
11806 QtDemuxStream *stream = qtdemux->streams[i];
11807 GstPad *oldpad = stream->pad;
11810 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
11811 i, stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
11813 if ((stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl) &&
11814 stream->track_id == qtdemux->chapters_track_id) {
11815 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
11816 so that it doesn't look like a subtitle track */
11817 gst_qtdemux_remove_stream (qtdemux, i);
11822 /* now we have all info and can expose */
11823 list = stream->stream_tags;
11824 stream->stream_tags = NULL;
11826 oldpads = g_slist_prepend (oldpads, oldpad);
11827 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
11828 return GST_FLOW_ERROR;
11831 gst_qtdemux_guess_bitrate (qtdemux);
11833 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
11835 for (iter = oldpads; iter; iter = g_slist_next (iter)) {
11836 GstPad *oldpad = iter->data;
11839 event = gst_event_new_eos ();
11840 if (qtdemux->segment_seqnum)
11841 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
11843 gst_pad_push_event (oldpad, event);
11844 gst_pad_set_active (oldpad, FALSE);
11845 gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
11846 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, oldpad);
11847 gst_object_unref (oldpad);
11850 /* check if we should post a redirect in case there is a single trak
11851 * and it is a redirecting trak */
11852 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
11855 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
11856 "an external content");
11857 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
11858 gst_structure_new ("redirect",
11859 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
11861 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
11862 qtdemux->posted_redirect = TRUE;
11865 for (i = 0; i < qtdemux->n_streams; i++) {
11866 QtDemuxStream *stream = qtdemux->streams[i];
11868 qtdemux_do_allocation (qtdemux, stream);
11871 qtdemux->exposed = TRUE;
11872 return GST_FLOW_OK;
11875 /* check if major or compatible brand is 3GP */
11876 static inline gboolean
11877 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
11880 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
11882 } else if (qtdemux->comp_brands != NULL) {
11886 gboolean res = FALSE;
11888 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
11891 while (size >= 4) {
11892 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
11897 gst_buffer_unmap (qtdemux->comp_brands, &map);
11904 /* check if tag is a spec'ed 3GP tag keyword storing a string */
11905 static inline gboolean
11906 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
11908 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
11909 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
11910 || fourcc == FOURCC_albm;
11914 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
11915 const char *tag, const char *dummy, GNode * node)
11917 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11921 gdouble longitude, latitude, altitude;
11924 len = QT_UINT32 (node->data);
11931 /* TODO: language code skipped */
11933 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
11936 /* do not alarm in trivial case, but bail out otherwise */
11937 if (*(data + offset) != 0) {
11938 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
11942 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
11943 GST_TAG_GEO_LOCATION_NAME, name, NULL);
11944 offset += strlen (name);
11948 if (len < offset + 2 + 4 + 4 + 4)
11951 /* +1 +1 = skip null-terminator and location role byte */
11953 /* table in spec says unsigned, semantics say negative has meaning ... */
11954 longitude = QT_SFP32 (data + offset);
11957 latitude = QT_SFP32 (data + offset);
11960 altitude = QT_SFP32 (data + offset);
11962 /* one invalid means all are invalid */
11963 if (longitude >= -180.0 && longitude <= 180.0 &&
11964 latitude >= -90.0 && latitude <= 90.0) {
11965 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
11966 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
11967 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
11968 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
11971 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
11978 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
11985 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
11986 const char *tag, const char *dummy, GNode * node)
11992 len = QT_UINT32 (node->data);
11996 y = QT_UINT16 ((guint8 *) node->data + 12);
11998 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
12001 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
12003 date = g_date_new_dmy (1, 1, y);
12004 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
12005 g_date_free (date);
12009 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
12010 const char *tag, const char *dummy, GNode * node)
12013 char *tag_str = NULL;
12018 len = QT_UINT32 (node->data);
12023 entity = (guint8 *) node->data + offset;
12024 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
12025 GST_DEBUG_OBJECT (qtdemux,
12026 "classification info: %c%c%c%c invalid classification entity",
12027 entity[0], entity[1], entity[2], entity[3]);
12032 table = QT_UINT16 ((guint8 *) node->data + offset);
12034 /* Language code skipped */
12038 /* Tag format: "XXXX://Y[YYYY]/classification info string"
12039 * XXXX: classification entity, fixed length 4 chars.
12040 * Y[YYYY]: classification table, max 5 chars.
12042 tag_str = g_strdup_printf ("----://%u/%s",
12043 table, (char *) node->data + offset);
12045 /* memcpy To be sure we're preserving byte order */
12046 memcpy (tag_str, entity, 4);
12047 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
12049 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
12058 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
12064 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
12065 const char *tag, const char *dummy, GNode * node)
12067 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12073 gboolean ret = TRUE;
12074 const gchar *charset = NULL;
12076 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12078 len = QT_UINT32 (data->data);
12079 type = QT_UINT32 ((guint8 *) data->data + 8);
12080 if (type == 0x00000001 && len > 16) {
12081 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
12084 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
12085 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
12088 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
12092 len = QT_UINT32 (node->data);
12093 type = QT_UINT32 ((guint8 *) node->data + 4);
12094 if ((type >> 24) == 0xa9 && len > 8 + 4) {
12098 /* Type starts with the (C) symbol, so the next data is a list
12099 * of (string size(16), language code(16), string) */
12101 str_len = QT_UINT16 ((guint8 *) node->data + 8);
12102 lang_code = QT_UINT16 ((guint8 *) node->data + 10);
12104 /* the string + fourcc + size + 2 16bit fields,
12105 * means that there are more tags in this atom */
12106 if (len > str_len + 8 + 4) {
12107 /* TODO how to represent the same tag in different languages? */
12108 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
12109 "text alternatives, reading only first one");
12113 len = MIN (len, str_len + 8 + 4); /* remove trailing strings that we don't use */
12114 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
12116 if (lang_code < 0x800) { /* MAC encoded string */
12119 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
12120 QT_FOURCC ((guint8 *) node->data + 4))) {
12121 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
12123 /* we go for 3GP style encoding if major brands claims so,
12124 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
12125 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
12126 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
12127 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
12129 /* 16-bit Language code is ignored here as well */
12130 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
12137 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
12138 ret = FALSE; /* may have to fallback */
12141 GError *err = NULL;
12143 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
12144 charset, NULL, NULL, &err);
12146 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
12147 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
12149 g_error_free (err);
12152 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
12153 len - offset, env_vars);
12156 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
12157 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
12161 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
12168 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
12169 const char *tag, const char *dummy, GNode * node)
12171 qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
12175 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
12176 const char *tag, const char *dummy, GNode * node)
12178 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12180 char *s, *t, *k = NULL;
12185 /* first try normal string tag if major brand not 3GP */
12186 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
12187 if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
12188 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
12189 * let's try it 3gpp way after minor safety check */
12191 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
12197 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
12201 len = QT_UINT32 (data);
12205 count = QT_UINT8 (data + 14);
12207 for (; count; count--) {
12210 if (offset + 1 > len)
12212 slen = QT_UINT8 (data + offset);
12214 if (offset + slen > len)
12216 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
12219 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
12221 t = g_strjoin (",", k, s, NULL);
12229 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
12236 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
12237 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
12246 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
12252 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
12253 const char *tag1, const char *tag2, GNode * node)
12260 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12262 len = QT_UINT32 (data->data);
12263 type = QT_UINT32 ((guint8 *) data->data + 8);
12264 if (type == 0x00000000 && len >= 22) {
12265 n1 = QT_UINT16 ((guint8 *) data->data + 18);
12266 n2 = QT_UINT16 ((guint8 *) data->data + 20);
12268 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
12269 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
12272 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
12273 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
12280 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
12281 const char *tag1, const char *dummy, GNode * node)
12288 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12290 len = QT_UINT32 (data->data);
12291 type = QT_UINT32 ((guint8 *) data->data + 8);
12292 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
12293 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
12294 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
12295 n1 = QT_UINT16 ((guint8 *) data->data + 16);
12297 /* do not add bpm=0 */
12298 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
12299 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
12307 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
12308 const char *tag1, const char *dummy, GNode * node)
12315 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12317 len = QT_UINT32 (data->data);
12318 type = QT_UINT32 ((guint8 *) data->data + 8);
12319 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
12320 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
12321 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
12322 num = QT_UINT32 ((guint8 *) data->data + 16);
12324 /* do not add num=0 */
12325 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
12326 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
12333 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
12334 const char *tag1, const char *dummy, GNode * node)
12341 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12343 len = QT_UINT32 (data->data);
12344 type = QT_UINT32 ((guint8 *) data->data + 8);
12345 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
12346 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
12347 GstTagImageType image_type;
12349 if (gst_tag_list_get_tag_size (taglist, GST_TAG_IMAGE) == 0)
12350 image_type = GST_TAG_IMAGE_TYPE_FRONT_COVER;
12352 image_type = GST_TAG_IMAGE_TYPE_NONE;
12355 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
12356 len - 16, image_type))) {
12357 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
12358 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
12359 gst_sample_unref (sample);
12366 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
12367 const char *tag, const char *dummy, GNode * node)
12374 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12376 len = QT_UINT32 (data->data);
12377 type = QT_UINT32 ((guint8 *) data->data + 8);
12378 if (type == 0x00000001 && len > 16) {
12379 guint y, m = 1, d = 1;
12382 s = g_strndup ((char *) data->data + 16, len - 16);
12383 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
12384 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
12385 if (ret >= 1 && y > 1500 && y < 3000) {
12388 date = g_date_new_dmy (d, m, y);
12389 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
12390 g_date_free (date);
12392 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
12400 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
12401 const char *tag, const char *dummy, GNode * node)
12405 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12407 /* re-route to normal string tag if major brand says so
12408 * or no data atom and compatible brand suggests so */
12409 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
12410 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
12411 qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
12416 guint len, type, n;
12418 len = QT_UINT32 (data->data);
12419 type = QT_UINT32 ((guint8 *) data->data + 8);
12420 if (type == 0x00000000 && len >= 18) {
12421 n = QT_UINT16 ((guint8 *) data->data + 16);
12423 const gchar *genre;
12425 genre = gst_tag_id3_genre_get (n - 1);
12426 if (genre != NULL) {
12427 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
12428 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
12436 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
12437 const gchar * tag, guint8 * data, guint32 datasize)
12442 /* make a copy to have \0 at the end */
12443 datacopy = g_strndup ((gchar *) data, datasize);
12445 /* convert the str to double */
12446 if (sscanf (datacopy, "%lf", &value) == 1) {
12447 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
12448 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
12450 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
12458 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
12459 const char *tag, const char *tag_bis, GNode * node)
12468 const gchar *meanstr;
12469 const gchar *namestr;
12471 /* checking the whole ---- atom size for consistency */
12472 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
12473 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
12477 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
12479 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
12483 meansize = QT_UINT32 (mean->data);
12484 if (meansize <= 12) {
12485 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
12488 meanstr = ((gchar *) mean->data) + 12;
12491 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
12493 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
12497 namesize = QT_UINT32 (name->data);
12498 if (namesize <= 12) {
12499 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
12502 namestr = ((gchar *) name->data) + 12;
12510 * uint24 - data type
12514 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12516 GST_WARNING_OBJECT (demux, "No data atom in this tag");
12519 datasize = QT_UINT32 (data->data);
12520 if (datasize <= 16) {
12521 GST_WARNING_OBJECT (demux, "Data atom too small");
12524 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
12526 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
12527 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
12528 static const struct
12530 const gchar name[28];
12531 const gchar tag[28];
12534 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
12535 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
12536 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
12537 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
12538 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
12539 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
12540 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
12541 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
12545 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
12546 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
12547 switch (gst_tag_get_type (tags[i].tag)) {
12548 case G_TYPE_DOUBLE:
12549 qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
12550 ((guint8 *) data->data) + 16, datasize - 16);
12552 case G_TYPE_STRING:
12553 qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
12562 if (i == G_N_ELEMENTS (tags))
12572 #ifndef GST_DISABLE_GST_DEBUG
12574 gchar *namestr_dbg;
12575 gchar *meanstr_dbg;
12577 meanstr_dbg = g_strndup (meanstr, meansize);
12578 namestr_dbg = g_strndup (namestr, namesize);
12580 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
12581 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
12583 g_free (namestr_dbg);
12584 g_free (meanstr_dbg);
12591 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
12592 const char *tag_bis, GNode * node)
12597 GstTagList *id32_taglist = NULL;
12599 GST_LOG_OBJECT (demux, "parsing ID32");
12602 len = GST_READ_UINT32_BE (data);
12604 /* need at least full box and language tag */
12608 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
12609 gst_buffer_fill (buf, 0, data + 14, len - 14);
12611 id32_taglist = gst_tag_list_from_id3v2_tag (buf);
12612 if (id32_taglist) {
12613 GST_LOG_OBJECT (demux, "parsing ok");
12614 gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
12615 gst_tag_list_unref (id32_taglist);
12617 GST_LOG_OBJECT (demux, "parsing failed");
12620 gst_buffer_unref (buf);
12623 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
12624 const char *tag, const char *tag_bis, GNode * node);
12627 FOURCC_pcst -> if media is a podcast -> bool
12628 FOURCC_cpil -> if media is part of a compilation -> bool
12629 FOURCC_pgap -> if media is part of a gapless context -> bool
12630 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
12633 static const struct
12636 const gchar *gst_tag;
12637 const gchar *gst_tag_bis;
12638 const GstQTDemuxAddTagFunc func;
12641 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
12642 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
12643 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
12644 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
12645 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
12646 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
12647 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
12648 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
12649 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
12650 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
12651 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
12652 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
12653 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
12654 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12655 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12656 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12657 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
12658 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
12659 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
12660 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
12661 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
12662 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
12663 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
12664 qtdemux_tag_add_num}, {
12665 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
12666 qtdemux_tag_add_num}, {
12667 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
12668 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
12669 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
12670 FOURCC_covr, GST_TAG_IMAGE, NULL, qtdemux_tag_add_covr}, {
12671 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
12672 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
12673 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
12674 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
12675 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
12676 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
12677 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
12678 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
12679 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
12680 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
12681 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
12682 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
12683 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
12684 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
12685 qtdemux_tag_add_classification}, {
12686 FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
12687 FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
12688 FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
12690 /* This is a special case, some tags are stored in this
12691 * 'reverse dns naming', according to:
12692 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
12695 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
12696 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
12697 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
12700 struct _GstQtDemuxTagList
12703 GstTagList *taglist;
12705 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
12708 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
12714 const gchar *style;
12719 GstQTDemux *demux = qtdemuxtaglist->demux;
12720 GstTagList *taglist = qtdemuxtaglist->taglist;
12723 len = QT_UINT32 (data);
12724 buf = gst_buffer_new_and_alloc (len);
12725 gst_buffer_fill (buf, 0, data, len);
12727 /* heuristic to determine style of tag */
12728 if (QT_FOURCC (data + 4) == FOURCC_____ ||
12729 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
12731 else if (demux->major_brand == FOURCC_qt__)
12732 style = "quicktime";
12733 /* fall back to assuming iso/3gp tag style */
12737 /* santize the name for the caps. */
12738 for (i = 0; i < 4; i++) {
12739 guint8 d = data[4 + i];
12740 if (g_ascii_isalnum (d))
12741 ndata[i] = g_ascii_tolower (d);
12746 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
12747 ndata[0], ndata[1], ndata[2], ndata[3]);
12748 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
12750 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
12751 sample = gst_sample_new (buf, NULL, NULL, s);
12752 gst_buffer_unref (buf);
12753 g_free (media_type);
12755 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
12758 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
12759 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
12761 gst_sample_unref (sample);
12765 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
12772 GstQtDemuxTagList demuxtaglist;
12774 demuxtaglist.demux = qtdemux;
12775 demuxtaglist.taglist = taglist;
12777 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
12778 if (meta != NULL) {
12779 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
12780 if (ilst == NULL) {
12781 GST_LOG_OBJECT (qtdemux, "no ilst");
12786 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
12790 while (i < G_N_ELEMENTS (add_funcs)) {
12791 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
12795 len = QT_UINT32 (node->data);
12797 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
12798 GST_FOURCC_ARGS (add_funcs[i].fourcc));
12800 add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
12801 add_funcs[i].gst_tag_bis, node);
12803 g_node_destroy (node);
12809 /* parsed nodes have been removed, pass along remainder as blob */
12810 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
12811 (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
12813 /* parse up XMP_ node if existing */
12814 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
12815 if (xmp_ != NULL) {
12817 GstTagList *xmptaglist;
12819 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
12820 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
12821 xmptaglist = gst_tag_list_from_xmp_buffer (buf);
12822 gst_buffer_unref (buf);
12824 qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
12826 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
12832 GstStructure *structure; /* helper for sort function */
12834 guint min_req_bitrate;
12835 guint min_req_qt_version;
12839 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
12841 GstQtReference *ref_a = (GstQtReference *) a;
12842 GstQtReference *ref_b = (GstQtReference *) b;
12844 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
12845 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
12847 /* known bitrates go before unknown; higher bitrates go first */
12848 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
12851 /* sort the redirects and post a message for the application.
12854 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
12856 GstQtReference *best;
12859 GValue list_val = { 0, };
12862 g_assert (references != NULL);
12864 references = g_list_sort (references, qtdemux_redirects_sort_func);
12866 best = (GstQtReference *) references->data;
12868 g_value_init (&list_val, GST_TYPE_LIST);
12870 for (l = references; l != NULL; l = l->next) {
12871 GstQtReference *ref = (GstQtReference *) l->data;
12872 GValue struct_val = { 0, };
12874 ref->structure = gst_structure_new ("redirect",
12875 "new-location", G_TYPE_STRING, ref->location, NULL);
12877 if (ref->min_req_bitrate > 0) {
12878 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
12879 ref->min_req_bitrate, NULL);
12882 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
12883 g_value_set_boxed (&struct_val, ref->structure);
12884 gst_value_list_append_value (&list_val, &struct_val);
12885 g_value_unset (&struct_val);
12886 /* don't free anything here yet, since we need best->structure below */
12889 g_assert (best != NULL);
12890 s = gst_structure_copy (best->structure);
12892 if (g_list_length (references) > 1) {
12893 gst_structure_set_value (s, "locations", &list_val);
12896 g_value_unset (&list_val);
12898 for (l = references; l != NULL; l = l->next) {
12899 GstQtReference *ref = (GstQtReference *) l->data;
12901 gst_structure_free (ref->structure);
12902 g_free (ref->location);
12905 g_list_free (references);
12907 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
12908 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
12909 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
12910 qtdemux->posted_redirect = TRUE;
12913 /* look for redirect nodes, collect all redirect information and
12917 qtdemux_parse_redirects (GstQTDemux * qtdemux)
12919 GNode *rmra, *rmda, *rdrf;
12921 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
12923 GList *redirects = NULL;
12925 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
12927 GstQtReference ref = { NULL, NULL, 0, 0 };
12928 GNode *rmdr, *rmvc;
12930 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
12931 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
12932 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
12933 ref.min_req_bitrate);
12936 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
12937 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
12938 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
12940 #ifndef GST_DISABLE_GST_DEBUG
12941 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
12943 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
12945 GST_LOG_OBJECT (qtdemux,
12946 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
12947 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
12948 bitmask, check_type);
12949 if (package == FOURCC_qtim && check_type == 0) {
12950 ref.min_req_qt_version = version;
12954 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
12960 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
12961 if (ref_len > 20) {
12962 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
12963 ref_data = (guint8 *) rdrf->data + 20;
12964 if (ref_type == FOURCC_alis) {
12965 guint record_len, record_version, fn_len;
12967 if (ref_len > 70) {
12968 /* MacOSX alias record, google for alias-layout.txt */
12969 record_len = QT_UINT16 (ref_data + 4);
12970 record_version = QT_UINT16 (ref_data + 4 + 2);
12971 fn_len = QT_UINT8 (ref_data + 50);
12972 if (record_len > 50 && record_version == 2 && fn_len > 0) {
12973 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
12976 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
12979 } else if (ref_type == FOURCC_url_) {
12980 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
12982 GST_DEBUG_OBJECT (qtdemux,
12983 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
12984 GST_FOURCC_ARGS (ref_type));
12986 if (ref.location != NULL) {
12987 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
12989 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
12991 GST_WARNING_OBJECT (qtdemux,
12992 "Failed to extract redirect location from rdrf atom");
12995 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
12999 /* look for others */
13000 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
13003 if (redirects != NULL) {
13004 qtdemux_process_redirects (qtdemux, redirects);
13010 static GstTagList *
13011 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
13015 if (tags == NULL) {
13016 tags = gst_tag_list_new_empty ();
13017 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
13020 if (qtdemux->major_brand == FOURCC_mjp2)
13021 fmt = "Motion JPEG 2000";
13022 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
13024 else if (qtdemux->major_brand == FOURCC_qt__)
13026 else if (qtdemux->fragmented)
13029 fmt = "ISO MP4/M4A";
13031 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
13032 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
13034 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
13040 /* we have read the complete moov node now.
13041 * This function parses all of the relevant info, creates the traks and
13042 * prepares all data structures for playback
13045 qtdemux_parse_tree (GstQTDemux * qtdemux)
13051 GstClockTime duration;
13053 guint64 creation_time;
13054 GstDateTime *datetime = NULL;
13057 /* make sure we have a usable taglist */
13058 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13060 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
13061 if (mvhd == NULL) {
13062 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
13063 return qtdemux_parse_redirects (qtdemux);
13066 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
13067 if (version == 1) {
13068 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
13069 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
13070 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
13071 } else if (version == 0) {
13072 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
13073 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
13074 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
13076 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
13080 /* Moving qt creation time (secs since 1904) to unix time */
13081 if (creation_time != 0) {
13082 /* Try to use epoch first as it should be faster and more commonly found */
13083 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
13086 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
13087 /* some data cleansing sanity */
13088 g_get_current_time (&now);
13089 if (now.tv_sec + 24 * 3600 < creation_time) {
13090 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
13092 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
13095 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
13096 GDateTime *dt, *dt_local;
13098 dt = g_date_time_add_seconds (base_dt, creation_time);
13099 dt_local = g_date_time_to_local (dt);
13100 datetime = gst_date_time_new_from_g_date_time (dt_local);
13102 g_date_time_unref (base_dt);
13103 g_date_time_unref (dt);
13107 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
13108 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
13110 gst_date_time_unref (datetime);
13113 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
13114 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
13116 /* check for fragmented file and get some (default) data */
13117 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
13120 GstByteReader mehd_data;
13122 /* let track parsing or anyone know weird stuff might happen ... */
13123 qtdemux->fragmented = TRUE;
13125 /* compensate for total duration */
13126 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
13128 qtdemux_parse_mehd (qtdemux, &mehd_data);
13131 /* set duration in the segment info */
13132 gst_qtdemux_get_duration (qtdemux, &duration);
13134 qtdemux->segment.duration = duration;
13135 /* also do not exceed duration; stop is set that way post seek anyway,
13136 * and segment activation falls back to duration,
13137 * whereas loop only checks stop, so let's align this here as well */
13138 qtdemux->segment.stop = duration;
13141 /* parse all traks */
13142 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
13144 qtdemux_parse_trak (qtdemux, trak);
13145 /* iterate all siblings */
13146 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
13149 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13152 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
13154 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13156 GST_LOG_OBJECT (qtdemux, "No udta node found.");
13159 /* maybe also some tags in meta box */
13160 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
13162 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
13163 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13165 GST_LOG_OBJECT (qtdemux, "No meta node found.");
13168 /* parse any protection system info */
13169 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
13171 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
13172 qtdemux_parse_pssh (qtdemux, pssh);
13173 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
13176 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
13181 /* taken from ffmpeg */
13183 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
13195 len = (len << 7) | (c & 0x7f);
13203 /* this can change the codec originally present in @list */
13205 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
13206 QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
13208 int len = QT_UINT32 (esds->data);
13209 guint8 *ptr = esds->data;
13210 guint8 *end = ptr + len;
13212 guint8 *data_ptr = NULL;
13214 guint8 object_type_id = 0;
13215 const char *codec_name = NULL;
13216 GstCaps *caps = NULL;
13218 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
13220 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
13222 while (ptr + 1 < end) {
13223 tag = QT_UINT8 (ptr);
13224 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
13226 len = read_descr_size (ptr, end, &ptr);
13227 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
13229 /* Check the stated amount of data is available for reading */
13230 if (len < 0 || ptr + len > end)
13234 case ES_DESCRIPTOR_TAG:
13235 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
13236 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
13239 case DECODER_CONFIG_DESC_TAG:{
13240 guint max_bitrate, avg_bitrate;
13242 object_type_id = QT_UINT8 (ptr);
13243 max_bitrate = QT_UINT32 (ptr + 5);
13244 avg_bitrate = QT_UINT32 (ptr + 9);
13245 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
13246 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
13247 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
13248 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
13249 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
13250 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
13251 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
13252 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
13254 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
13255 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
13256 avg_bitrate, NULL);
13261 case DECODER_SPECIFIC_INFO_TAG:
13262 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
13263 if (object_type_id == 0xe0 && len == 0x40) {
13269 GST_DEBUG_OBJECT (qtdemux,
13270 "Have VOBSUB palette. Creating palette event");
13271 /* move to decConfigDescr data and read palette */
13273 for (i = 0; i < 16; i++) {
13274 clut[i] = QT_UINT32 (data);
13278 s = gst_structure_new ("application/x-gst-dvd", "event",
13279 G_TYPE_STRING, "dvd-spu-clut-change",
13280 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
13281 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
13282 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
13283 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
13284 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
13285 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
13286 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
13287 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
13290 /* store event and trigger custom processing */
13291 stream->pending_event =
13292 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
13294 /* Generic codec_data handler puts it on the caps */
13301 case SL_CONFIG_DESC_TAG:
13302 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
13306 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
13308 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
13314 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
13315 * in use, and should also be used to override some other parameters for some
13317 switch (object_type_id) {
13318 case 0x20: /* MPEG-4 */
13319 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
13320 * profile_and_level_indication */
13321 if (data_ptr != NULL && data_len >= 5 &&
13322 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
13323 gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
13324 data_ptr + 4, data_len - 4);
13326 break; /* Nothing special needed here */
13327 case 0x21: /* H.264 */
13328 codec_name = "H.264 / AVC";
13329 caps = gst_caps_new_simple ("video/x-h264",
13330 "stream-format", G_TYPE_STRING, "avc",
13331 "alignment", G_TYPE_STRING, "au", NULL);
13333 case 0x40: /* AAC (any) */
13334 case 0x66: /* AAC Main */
13335 case 0x67: /* AAC LC */
13336 case 0x68: /* AAC SSR */
13337 /* Override channels and rate based on the codec_data, as it's often
13339 /* Only do so for basic setup without HE-AAC extension */
13340 if (data_ptr && data_len == 2) {
13341 guint channels, rate;
13343 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
13345 entry->n_channels = channels;
13347 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
13349 entry->rate = rate;
13352 /* Set level and profile if possible */
13353 if (data_ptr != NULL && data_len >= 2) {
13354 gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
13355 data_ptr, data_len);
13357 const gchar *profile_str = NULL;
13360 guint8 *codec_data;
13361 gint rate_idx, profile;
13363 /* No codec_data, let's invent something.
13364 * FIXME: This is wrong for SBR! */
13366 GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
13368 buffer = gst_buffer_new_and_alloc (2);
13369 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
13370 codec_data = map.data;
13373 gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
13376 switch (object_type_id) {
13378 profile_str = "main";
13382 profile_str = "lc";
13386 profile_str = "ssr";
13394 codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
13396 ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
13398 gst_buffer_unmap (buffer, &map);
13399 gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
13400 GST_TYPE_BUFFER, buffer, NULL);
13401 gst_buffer_unref (buffer);
13404 gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
13405 G_TYPE_STRING, profile_str, NULL);
13409 case 0x60: /* MPEG-2, various profiles */
13415 codec_name = "MPEG-2 video";
13416 caps = gst_caps_new_simple ("video/mpeg",
13417 "mpegversion", G_TYPE_INT, 2,
13418 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13420 case 0x69: /* MPEG-2 BC audio */
13421 case 0x6B: /* MPEG-1 audio */
13422 caps = gst_caps_new_simple ("audio/mpeg",
13423 "mpegversion", G_TYPE_INT, 1, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
13424 codec_name = "MPEG-1 audio";
13426 case 0x6A: /* MPEG-1 */
13427 codec_name = "MPEG-1 video";
13428 caps = gst_caps_new_simple ("video/mpeg",
13429 "mpegversion", G_TYPE_INT, 1,
13430 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13432 case 0x6C: /* MJPEG */
13434 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13436 codec_name = "Motion-JPEG";
13438 case 0x6D: /* PNG */
13440 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
13442 codec_name = "PNG still images";
13444 case 0x6E: /* JPEG2000 */
13445 codec_name = "JPEG-2000";
13446 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
13448 case 0xA4: /* Dirac */
13449 codec_name = "Dirac";
13450 caps = gst_caps_new_empty_simple ("video/x-dirac");
13452 case 0xA5: /* AC3 */
13453 codec_name = "AC-3 audio";
13454 caps = gst_caps_new_simple ("audio/x-ac3",
13455 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13457 case 0xA9: /* AC3 */
13458 codec_name = "DTS audio";
13459 caps = gst_caps_new_simple ("audio/x-dts",
13460 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13462 case 0xE1: /* QCELP */
13463 /* QCELP, the codec_data is a riff tag (little endian) with
13464 * 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). */
13465 caps = gst_caps_new_empty_simple ("audio/qcelp");
13466 codec_name = "QCELP";
13472 /* If we have a replacement caps, then change our caps for this stream */
13474 gst_caps_unref (entry->caps);
13475 entry->caps = caps;
13478 if (codec_name && list)
13479 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
13480 GST_TAG_AUDIO_CODEC, codec_name, NULL);
13482 /* Add the codec_data attribute to caps, if we have it */
13486 buffer = gst_buffer_new_and_alloc (data_len);
13487 gst_buffer_fill (buffer, 0, data_ptr, data_len);
13489 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
13490 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
13492 gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
13494 gst_buffer_unref (buffer);
13499 static inline GstCaps *
13500 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
13504 char *s, fourstr[5];
13506 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13507 for (i = 0; i < 4; i++) {
13508 if (!g_ascii_isalnum (fourstr[i]))
13511 s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
13512 caps = gst_caps_new_empty_simple (s);
13517 #define _codec(name) \
13519 if (codec_name) { \
13520 *codec_name = g_strdup (name); \
13525 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13526 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
13527 const guint8 * stsd_entry_data, gchar ** codec_name)
13529 GstCaps *caps = NULL;
13530 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
13533 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
13534 _codec ("PNG still images");
13535 caps = gst_caps_new_empty_simple ("image/png");
13538 _codec ("JPEG still images");
13540 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13543 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
13544 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
13545 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
13546 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
13547 _codec ("Motion-JPEG");
13549 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13552 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
13553 _codec ("Motion-JPEG format B");
13554 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
13557 _codec ("JPEG-2000");
13558 /* override to what it should be according to spec, avoid palette_data */
13559 entry->bits_per_sample = 24;
13560 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
13563 _codec ("Sorensen video v.3");
13564 caps = gst_caps_new_simple ("video/x-svq",
13565 "svqversion", G_TYPE_INT, 3, NULL);
13567 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
13568 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
13569 _codec ("Sorensen video v.1");
13570 caps = gst_caps_new_simple ("video/x-svq",
13571 "svqversion", G_TYPE_INT, 1, NULL);
13573 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
13574 caps = gst_caps_new_empty_simple ("video/x-raw");
13575 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
13576 _codec ("Windows Raw RGB");
13577 stream->alignment = 32;
13583 bps = QT_UINT16 (stsd_entry_data + 82);
13586 format = GST_VIDEO_FORMAT_RGB15;
13589 format = GST_VIDEO_FORMAT_RGB16;
13592 format = GST_VIDEO_FORMAT_RGB;
13595 format = GST_VIDEO_FORMAT_ARGB;
13603 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
13604 format = GST_VIDEO_FORMAT_I420;
13606 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
13607 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
13608 format = GST_VIDEO_FORMAT_I420;
13611 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
13612 format = GST_VIDEO_FORMAT_UYVY;
13614 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
13615 format = GST_VIDEO_FORMAT_v308;
13617 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
13618 format = GST_VIDEO_FORMAT_v216;
13621 format = GST_VIDEO_FORMAT_v210;
13623 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
13624 format = GST_VIDEO_FORMAT_r210;
13626 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
13627 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
13628 format = GST_VIDEO_FORMAT_v410;
13631 /* Packed YUV 4:4:4:4 8 bit in 32 bits
13632 * but different order than AYUV
13633 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
13634 format = GST_VIDEO_FORMAT_v408;
13637 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
13638 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
13639 _codec ("MPEG-1 video");
13640 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
13641 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13643 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
13644 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
13645 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
13646 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
13647 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
13648 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
13649 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
13650 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
13651 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
13652 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
13653 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
13654 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
13655 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
13656 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
13657 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
13658 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
13659 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
13660 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
13661 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
13662 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
13663 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
13664 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
13665 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
13666 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
13667 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
13668 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
13669 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
13670 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
13671 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
13672 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
13673 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
13674 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
13675 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
13676 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
13677 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
13678 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
13679 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
13680 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
13681 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
13682 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
13683 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
13684 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
13685 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
13686 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
13687 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
13688 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
13689 case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
13690 _codec ("MPEG-2 video");
13691 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
13692 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13694 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
13695 _codec ("GIF still images");
13696 caps = gst_caps_new_empty_simple ("image/gif");
13699 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
13701 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
13703 /* ffmpeg uses the height/width props, don't know why */
13704 caps = gst_caps_new_simple ("video/x-h263",
13705 "variant", G_TYPE_STRING, "itu", NULL);
13709 _codec ("MPEG-4 video");
13710 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
13711 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13713 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
13714 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
13715 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
13716 caps = gst_caps_new_simple ("video/x-msmpeg",
13717 "msmpegversion", G_TYPE_INT, 43, NULL);
13719 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
13721 caps = gst_caps_new_simple ("video/x-divx",
13722 "divxversion", G_TYPE_INT, 3, NULL);
13724 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
13725 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
13727 caps = gst_caps_new_simple ("video/x-divx",
13728 "divxversion", G_TYPE_INT, 4, NULL);
13730 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
13732 caps = gst_caps_new_simple ("video/x-divx",
13733 "divxversion", G_TYPE_INT, 5, NULL);
13736 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
13738 caps = gst_caps_new_simple ("video/x-ffv",
13739 "ffvversion", G_TYPE_INT, 1, NULL);
13742 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
13743 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
13748 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
13749 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
13750 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13754 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
13755 _codec ("Cinepak");
13756 caps = gst_caps_new_empty_simple ("video/x-cinepak");
13758 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
13759 _codec ("Apple QuickDraw");
13760 caps = gst_caps_new_empty_simple ("video/x-qdrw");
13762 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
13763 _codec ("Apple video");
13764 caps = gst_caps_new_empty_simple ("video/x-apple-video");
13768 _codec ("H.264 / AVC");
13769 caps = gst_caps_new_simple ("video/x-h264",
13770 "stream-format", G_TYPE_STRING, "avc",
13771 "alignment", G_TYPE_STRING, "au", NULL);
13774 _codec ("H.264 / AVC");
13775 caps = gst_caps_new_simple ("video/x-h264",
13776 "stream-format", G_TYPE_STRING, "avc3",
13777 "alignment", G_TYPE_STRING, "au", NULL);
13781 _codec ("H.265 / HEVC");
13782 caps = gst_caps_new_simple ("video/x-h265",
13783 "stream-format", G_TYPE_STRING, "hvc1",
13784 "alignment", G_TYPE_STRING, "au", NULL);
13787 _codec ("H.265 / HEVC");
13788 caps = gst_caps_new_simple ("video/x-h265",
13789 "stream-format", G_TYPE_STRING, "hev1",
13790 "alignment", G_TYPE_STRING, "au", NULL);
13793 _codec ("Run-length encoding");
13794 caps = gst_caps_new_simple ("video/x-rle",
13795 "layout", G_TYPE_STRING, "quicktime", NULL);
13798 _codec ("Run-length encoding");
13799 caps = gst_caps_new_simple ("video/x-rle",
13800 "layout", G_TYPE_STRING, "microsoft", NULL);
13802 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
13803 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
13804 _codec ("Indeo Video 3");
13805 caps = gst_caps_new_simple ("video/x-indeo",
13806 "indeoversion", G_TYPE_INT, 3, NULL);
13808 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
13809 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
13810 _codec ("Intel Video 4");
13811 caps = gst_caps_new_simple ("video/x-indeo",
13812 "indeoversion", G_TYPE_INT, 4, NULL);
13816 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
13817 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
13818 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
13819 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
13820 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
13821 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
13822 _codec ("DV Video");
13823 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
13824 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13826 case FOURCC_dv5n: /* DVCPRO50 NTSC */
13827 case FOURCC_dv5p: /* DVCPRO50 PAL */
13828 _codec ("DVCPro50 Video");
13829 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
13830 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13832 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
13833 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
13834 _codec ("DVCProHD Video");
13835 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
13836 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13838 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
13839 _codec ("Apple Graphics (SMC)");
13840 caps = gst_caps_new_empty_simple ("video/x-smc");
13842 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
13844 caps = gst_caps_new_empty_simple ("video/x-vp3");
13846 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
13847 _codec ("VP6 Flash");
13848 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
13852 caps = gst_caps_new_empty_simple ("video/x-theora");
13853 /* theora uses one byte of padding in the data stream because it does not
13854 * allow 0 sized packets while theora does */
13855 entry->padding = 1;
13859 caps = gst_caps_new_empty_simple ("video/x-dirac");
13861 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
13862 _codec ("TIFF still images");
13863 caps = gst_caps_new_empty_simple ("image/tiff");
13865 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
13866 _codec ("Apple Intermediate Codec");
13867 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
13869 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
13870 _codec ("AVID DNxHD");
13871 caps = gst_caps_from_string ("video/x-dnxhd");
13874 _codec ("On2 VP8");
13875 caps = gst_caps_from_string ("video/x-vp8");
13878 _codec ("Apple ProRes LT");
13880 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
13884 _codec ("Apple ProRes HQ");
13886 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
13890 _codec ("Apple ProRes");
13892 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13896 _codec ("Apple ProRes Proxy");
13898 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13902 _codec ("Apple ProRes 4444");
13904 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13908 _codec ("Apple ProRes 4444 XQ");
13910 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13914 _codec ("GoPro CineForm");
13915 caps = gst_caps_from_string ("video/x-cineform");
13920 caps = gst_caps_new_simple ("video/x-wmv",
13921 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
13923 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
13926 caps = _get_unknown_codec_name ("video", fourcc);
13931 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
13934 gst_video_info_init (&info);
13935 gst_video_info_set_format (&info, format, entry->width, entry->height);
13937 caps = gst_video_info_to_caps (&info);
13938 *codec_name = gst_pb_utils_get_codec_description (caps);
13940 /* enable clipping for raw video streams */
13941 stream->need_clip = TRUE;
13942 stream->alignment = 32;
13949 round_up_pow2 (guint n)
13961 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13962 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
13963 int len, gchar ** codec_name)
13966 const GstStructure *s;
13969 GstAudioFormat format = 0;
13972 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
13974 depth = entry->bytes_per_packet * 8;
13977 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
13979 /* 8-bit audio is unsigned */
13981 format = GST_AUDIO_FORMAT_U8;
13982 /* otherwise it's signed and big-endian just like 'twos' */
13984 endian = G_BIG_ENDIAN;
13991 endian = G_LITTLE_ENDIAN;
13994 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
13996 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
14000 caps = gst_caps_new_simple ("audio/x-raw",
14001 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14002 "layout", G_TYPE_STRING, "interleaved", NULL);
14003 stream->alignment = GST_ROUND_UP_8 (depth);
14004 stream->alignment = round_up_pow2 (stream->alignment);
14007 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
14008 _codec ("Raw 64-bit floating-point audio");
14009 caps = gst_caps_new_simple ("audio/x-raw",
14010 "format", G_TYPE_STRING, "F64BE",
14011 "layout", G_TYPE_STRING, "interleaved", NULL);
14012 stream->alignment = 8;
14014 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
14015 _codec ("Raw 32-bit floating-point audio");
14016 caps = gst_caps_new_simple ("audio/x-raw",
14017 "format", G_TYPE_STRING, "F32BE",
14018 "layout", G_TYPE_STRING, "interleaved", NULL);
14019 stream->alignment = 4;
14022 _codec ("Raw 24-bit PCM audio");
14023 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14025 caps = gst_caps_new_simple ("audio/x-raw",
14026 "format", G_TYPE_STRING, "S24BE",
14027 "layout", G_TYPE_STRING, "interleaved", NULL);
14028 stream->alignment = 4;
14030 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
14031 _codec ("Raw 32-bit PCM audio");
14032 caps = gst_caps_new_simple ("audio/x-raw",
14033 "format", G_TYPE_STRING, "S32BE",
14034 "layout", G_TYPE_STRING, "interleaved", NULL);
14035 stream->alignment = 4;
14037 case GST_MAKE_FOURCC ('s', '1', '6', 'l'):
14038 _codec ("Raw 16-bit PCM audio");
14039 caps = gst_caps_new_simple ("audio/x-raw",
14040 "format", G_TYPE_STRING, "S16LE",
14041 "layout", G_TYPE_STRING, "interleaved", NULL);
14042 stream->alignment = 2;
14045 _codec ("Mu-law audio");
14046 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
14049 _codec ("A-law audio");
14050 caps = gst_caps_new_empty_simple ("audio/x-alaw");
14054 _codec ("Microsoft ADPCM");
14055 /* Microsoft ADPCM-ACM code 2 */
14056 caps = gst_caps_new_simple ("audio/x-adpcm",
14057 "layout", G_TYPE_STRING, "microsoft", NULL);
14061 _codec ("DVI/IMA ADPCM");
14062 caps = gst_caps_new_simple ("audio/x-adpcm",
14063 "layout", G_TYPE_STRING, "dvi", NULL);
14067 _codec ("DVI/Intel IMA ADPCM");
14068 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
14069 caps = gst_caps_new_simple ("audio/x-adpcm",
14070 "layout", G_TYPE_STRING, "quicktime", NULL);
14074 /* MPEG layer 3, CBR only (pre QT4.1) */
14076 _codec ("MPEG-1 layer 3");
14077 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
14078 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
14079 "mpegversion", G_TYPE_INT, 1, NULL);
14081 case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
14082 _codec ("MPEG-1 layer 2");
14084 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
14085 "mpegversion", G_TYPE_INT, 1, NULL);
14088 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
14089 _codec ("EAC-3 audio");
14090 caps = gst_caps_new_simple ("audio/x-eac3",
14091 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14092 entry->sampled = TRUE;
14094 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
14096 _codec ("AC-3 audio");
14097 caps = gst_caps_new_simple ("audio/x-ac3",
14098 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14099 entry->sampled = TRUE;
14101 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
14102 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
14103 _codec ("DTS audio");
14104 caps = gst_caps_new_simple ("audio/x-dts",
14105 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14106 entry->sampled = TRUE;
14108 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
14109 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
14110 _codec ("DTS-HD audio");
14111 caps = gst_caps_new_simple ("audio/x-dts",
14112 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14113 entry->sampled = TRUE;
14117 caps = gst_caps_new_simple ("audio/x-mace",
14118 "maceversion", G_TYPE_INT, 3, NULL);
14122 caps = gst_caps_new_simple ("audio/x-mace",
14123 "maceversion", G_TYPE_INT, 6, NULL);
14125 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
14127 caps = gst_caps_new_empty_simple ("application/ogg");
14129 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
14130 _codec ("DV audio");
14131 caps = gst_caps_new_empty_simple ("audio/x-dv");
14134 _codec ("MPEG-4 AAC audio");
14135 caps = gst_caps_new_simple ("audio/mpeg",
14136 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
14137 "stream-format", G_TYPE_STRING, "raw", NULL);
14139 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
14140 _codec ("QDesign Music");
14141 caps = gst_caps_new_empty_simple ("audio/x-qdm");
14144 _codec ("QDesign Music v.2");
14145 /* FIXME: QDesign music version 2 (no constant) */
14146 if (FALSE && data) {
14147 caps = gst_caps_new_simple ("audio/x-qdm2",
14148 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
14149 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
14150 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
14152 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
14156 _codec ("GSM audio");
14157 caps = gst_caps_new_empty_simple ("audio/x-gsm");
14160 _codec ("AMR audio");
14161 caps = gst_caps_new_empty_simple ("audio/AMR");
14164 _codec ("AMR-WB audio");
14165 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
14168 _codec ("Quicktime IMA ADPCM");
14169 caps = gst_caps_new_simple ("audio/x-adpcm",
14170 "layout", G_TYPE_STRING, "quicktime", NULL);
14173 _codec ("Apple lossless audio");
14174 caps = gst_caps_new_empty_simple ("audio/x-alac");
14177 _codec ("Free Lossless Audio Codec");
14178 caps = gst_caps_new_simple ("audio/x-flac",
14179 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14181 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
14182 _codec ("QualComm PureVoice");
14183 caps = gst_caps_from_string ("audio/qcelp");
14188 caps = gst_caps_new_empty_simple ("audio/x-wma");
14192 caps = gst_caps_new_empty_simple ("audio/x-opus");
14194 case GST_MAKE_FOURCC ('l', 'p', 'c', 'm'):
14199 GstAudioFormat format;
14202 FLAG_IS_FLOAT = 0x1,
14203 FLAG_IS_BIG_ENDIAN = 0x2,
14204 FLAG_IS_SIGNED = 0x4,
14205 FLAG_IS_PACKED = 0x8,
14206 FLAG_IS_ALIGNED_HIGH = 0x10,
14207 FLAG_IS_NON_INTERLEAVED = 0x20
14209 _codec ("Raw LPCM audio");
14211 if (data && len >= 56) {
14212 depth = QT_UINT32 (data + 40);
14213 flags = QT_UINT32 (data + 44);
14214 width = QT_UINT32 (data + 48) * 8 / entry->n_channels;
14216 if ((flags & FLAG_IS_FLOAT) == 0) {
14221 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
14222 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
14223 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
14224 caps = gst_caps_new_simple ("audio/x-raw",
14225 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14226 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
14227 "non-interleaved" : "interleaved", NULL);
14228 stream->alignment = GST_ROUND_UP_8 (depth);
14229 stream->alignment = round_up_pow2 (stream->alignment);
14234 if (flags & FLAG_IS_BIG_ENDIAN)
14235 format = GST_AUDIO_FORMAT_F64BE;
14237 format = GST_AUDIO_FORMAT_F64LE;
14239 if (flags & FLAG_IS_BIG_ENDIAN)
14240 format = GST_AUDIO_FORMAT_F32BE;
14242 format = GST_AUDIO_FORMAT_F32LE;
14244 caps = gst_caps_new_simple ("audio/x-raw",
14245 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14246 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
14247 "non-interleaved" : "interleaved", NULL);
14248 stream->alignment = width / 8;
14252 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
14256 caps = _get_unknown_codec_name ("audio", fourcc);
14262 GstCaps *templ_caps =
14263 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
14264 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
14265 gst_caps_unref (caps);
14266 gst_caps_unref (templ_caps);
14267 caps = intersection;
14270 /* enable clipping for raw audio streams */
14271 s = gst_caps_get_structure (caps, 0);
14272 name = gst_structure_get_name (s);
14273 if (g_str_has_prefix (name, "audio/x-raw")) {
14274 stream->need_clip = TRUE;
14275 stream->max_buffer_size = 4096 * entry->bytes_per_frame;
14276 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
14282 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14283 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14284 const guint8 * stsd_entry_data, gchar ** codec_name)
14288 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14292 _codec ("DVD subtitle");
14293 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
14294 stream->need_process = TRUE;
14297 _codec ("Quicktime timed text");
14300 _codec ("3GPP timed text");
14302 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
14304 /* actual text piece needs to be extracted */
14305 stream->need_process = TRUE;
14308 _codec ("XML subtitles");
14309 caps = gst_caps_new_empty_simple ("application/ttml+xml");
14313 caps = _get_unknown_codec_name ("text", fourcc);
14321 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14322 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14323 const guint8 * stsd_entry_data, gchar ** codec_name)
14329 _codec ("MPEG 1 video");
14330 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14331 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14341 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
14342 const gchar * system_id)
14346 if (!qtdemux->protection_system_ids)
14347 qtdemux->protection_system_ids =
14348 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
14349 /* Check whether we already have an entry for this system ID. */
14350 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
14351 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
14352 if (g_ascii_strcasecmp (system_id, id) == 0) {
14356 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
14357 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,