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 if (G_UNLIKELY (stream->stsd_sample_description_id >=
7968 stream->stsd_entries_length)) {
7969 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7970 (_("This file is invalid and cannot be played.")),
7971 ("New sample description id is out of bounds (%d >= %d)",
7972 stream->stsd_sample_description_id, stream->stsd_entries_length));
7974 stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
7975 stream->new_caps = TRUE;
7980 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
7981 QtDemuxStream * stream, GstTagList * list)
7983 gboolean ret = TRUE;
7984 /* consistent default for push based mode */
7985 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
7987 if (stream->subtype == FOURCC_vide) {
7988 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
7991 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
7994 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7995 gst_object_unref (stream->pad);
8001 qtdemux->n_video_streams++;
8002 } else if (stream->subtype == FOURCC_soun) {
8003 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
8006 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
8008 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8009 gst_object_unref (stream->pad);
8014 qtdemux->n_audio_streams++;
8015 } else if (stream->subtype == FOURCC_strm) {
8016 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
8017 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
8018 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
8019 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
8022 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
8024 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8025 gst_object_unref (stream->pad);
8030 qtdemux->n_sub_streams++;
8031 } else if (CUR_STREAM (stream)->caps) {
8032 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8035 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8037 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8038 gst_object_unref (stream->pad);
8043 qtdemux->n_video_streams++;
8045 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
8052 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
8053 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
8054 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
8055 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
8057 if (stream->stream_tags)
8058 gst_tag_list_unref (stream->stream_tags);
8059 stream->stream_tags = list;
8061 /* global tags go on each pad anyway */
8062 stream->send_global_tags = TRUE;
8063 /* send upstream GST_EVENT_PROTECTION events that were received before
8064 this source pad was created */
8065 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
8066 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
8070 gst_tag_list_unref (list);
8074 /* find next atom with @fourcc starting at @offset */
8075 static GstFlowReturn
8076 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
8077 guint64 * length, guint32 fourcc)
8083 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
8084 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
8090 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
8091 if (G_UNLIKELY (ret != GST_FLOW_OK))
8093 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
8096 gst_buffer_unref (buf);
8099 gst_buffer_map (buf, &map, GST_MAP_READ);
8100 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
8101 gst_buffer_unmap (buf, &map);
8102 gst_buffer_unref (buf);
8104 if (G_UNLIKELY (*length == 0)) {
8105 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
8106 ret = GST_FLOW_ERROR;
8110 if (lfourcc == fourcc) {
8111 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
8115 GST_LOG_OBJECT (qtdemux,
8116 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
8117 GST_FOURCC_ARGS (fourcc), *offset);
8126 /* might simply have had last one */
8127 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
8132 /* should only do something in pull mode */
8133 /* call with OBJECT lock */
8134 static GstFlowReturn
8135 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
8137 guint64 length, offset;
8138 GstBuffer *buf = NULL;
8139 GstFlowReturn ret = GST_FLOW_OK;
8140 GstFlowReturn res = GST_FLOW_OK;
8143 offset = qtdemux->moof_offset;
8144 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
8147 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8148 return GST_FLOW_EOS;
8151 /* best not do pull etc with lock held */
8152 GST_OBJECT_UNLOCK (qtdemux);
8154 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8155 if (ret != GST_FLOW_OK)
8158 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
8159 if (G_UNLIKELY (ret != GST_FLOW_OK))
8161 gst_buffer_map (buf, &map, GST_MAP_READ);
8162 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
8163 gst_buffer_unmap (buf, &map);
8164 gst_buffer_unref (buf);
8169 gst_buffer_unmap (buf, &map);
8170 gst_buffer_unref (buf);
8174 /* look for next moof */
8175 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8176 if (G_UNLIKELY (ret != GST_FLOW_OK))
8180 GST_OBJECT_LOCK (qtdemux);
8182 qtdemux->moof_offset = offset;
8188 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
8190 res = GST_FLOW_ERROR;
8195 /* maybe upstream temporarily flushing */
8196 if (ret != GST_FLOW_FLUSHING) {
8197 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8200 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
8201 /* resume at current position next time */
8208 /* initialise bytereaders for stbl sub-atoms */
8210 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
8212 stream->stbl_index = -1; /* no samples have yet been parsed */
8213 stream->sample_index = -1;
8215 /* time-to-sample atom */
8216 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
8219 /* copy atom data into a new buffer for later use */
8220 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
8222 /* skip version + flags */
8223 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
8224 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
8226 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
8228 /* make sure there's enough data */
8229 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
8230 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
8231 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
8232 stream->n_sample_times);
8233 if (!stream->n_sample_times)
8237 /* sync sample atom */
8238 stream->stps_present = FALSE;
8239 if ((stream->stss_present =
8240 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
8241 &stream->stss) ? TRUE : FALSE) == TRUE) {
8242 /* copy atom data into a new buffer for later use */
8243 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
8245 /* skip version + flags */
8246 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
8247 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
8250 if (stream->n_sample_syncs) {
8251 /* make sure there's enough data */
8252 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
8256 /* partial sync sample atom */
8257 if ((stream->stps_present =
8258 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
8259 &stream->stps) ? TRUE : FALSE) == TRUE) {
8260 /* copy atom data into a new buffer for later use */
8261 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
8263 /* skip version + flags */
8264 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
8265 !gst_byte_reader_get_uint32_be (&stream->stps,
8266 &stream->n_sample_partial_syncs))
8269 /* if there are no entries, the stss table contains the real
8271 if (stream->n_sample_partial_syncs) {
8272 /* make sure there's enough data */
8273 if (!qt_atom_parser_has_chunks (&stream->stps,
8274 stream->n_sample_partial_syncs, 4))
8281 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
8284 /* copy atom data into a new buffer for later use */
8285 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
8287 /* skip version + flags */
8288 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
8289 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
8292 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
8295 if (!stream->n_samples)
8298 /* sample-to-chunk atom */
8299 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
8302 /* copy atom data into a new buffer for later use */
8303 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
8305 /* skip version + flags */
8306 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
8307 !gst_byte_reader_get_uint32_be (&stream->stsc,
8308 &stream->n_samples_per_chunk))
8311 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
8312 stream->n_samples_per_chunk);
8314 /* make sure there's enough data */
8315 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
8321 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
8322 stream->co_size = sizeof (guint32);
8323 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
8325 stream->co_size = sizeof (guint64);
8329 /* copy atom data into a new buffer for later use */
8330 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
8332 /* skip version + flags */
8333 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
8336 /* chunks_are_samples == TRUE means treat chunks as samples */
8337 stream->chunks_are_samples = stream->sample_size
8338 && !CUR_STREAM (stream)->sampled;
8339 if (stream->chunks_are_samples) {
8340 /* treat chunks as samples */
8341 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
8344 /* skip number of entries */
8345 if (!gst_byte_reader_skip (&stream->stco, 4))
8348 /* make sure there are enough data in the stsz atom */
8349 if (!stream->sample_size) {
8350 /* different sizes for each sample */
8351 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
8356 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
8357 stream->n_samples, (guint) sizeof (QtDemuxSample),
8358 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
8360 if (stream->n_samples >=
8361 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
8362 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
8363 "be larger than %uMB (broken file?)", stream->n_samples,
8364 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
8368 g_assert (stream->samples == NULL);
8369 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
8370 if (!stream->samples) {
8371 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
8376 /* composition time-to-sample */
8377 if ((stream->ctts_present =
8378 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
8379 &stream->ctts) ? TRUE : FALSE) == TRUE) {
8380 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
8382 /* copy atom data into a new buffer for later use */
8383 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
8385 /* skip version + flags */
8386 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
8387 || !gst_byte_reader_get_uint32_be (&stream->ctts,
8388 &stream->n_composition_times))
8391 /* make sure there's enough data */
8392 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
8396 /* This is optional, if missing we iterate the ctts */
8397 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
8398 if (!gst_byte_reader_skip (&cslg, 1 + 3)
8399 || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
8400 g_free ((gpointer) cslg.data);
8404 gint32 cslg_least = 0;
8405 guint num_entries, pos;
8408 pos = gst_byte_reader_get_pos (&stream->ctts);
8409 num_entries = stream->n_composition_times;
8411 stream->cslg_shift = 0;
8413 for (i = 0; i < num_entries; i++) {
8416 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
8417 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8419 if (offset < cslg_least)
8420 cslg_least = offset;
8424 stream->cslg_shift = ABS (cslg_least);
8426 stream->cslg_shift = 0;
8428 /* reset the reader so we can generate sample table */
8429 gst_byte_reader_set_pos (&stream->ctts, pos);
8432 /* Ensure the cslg_shift value is consistent so we can use it
8433 * unconditionnally to produce TS and Segment */
8434 stream->cslg_shift = 0;
8441 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8442 (_("This file is corrupt and cannot be played.")), (NULL));
8447 gst_qtdemux_stbl_free (stream);
8448 if (!qtdemux->fragmented) {
8449 /* not quite good */
8450 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
8453 /* may pick up samples elsewhere */
8459 /* collect samples from the next sample to be parsed up to sample @n for @stream
8460 * by reading the info from @stbl
8462 * This code can be executed from both the streaming thread and the seeking
8463 * thread so it takes the object lock to protect itself
8466 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
8469 QtDemuxSample *samples, *first, *cur, *last;
8470 guint32 n_samples_per_chunk;
8473 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
8474 GST_FOURCC_FORMAT ", pad %s",
8475 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
8476 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
8478 n_samples = stream->n_samples;
8481 goto out_of_samples;
8483 GST_OBJECT_LOCK (qtdemux);
8484 if (n <= stream->stbl_index)
8485 goto already_parsed;
8487 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
8489 if (!stream->stsz.data) {
8490 /* so we already parsed and passed all the moov samples;
8491 * onto fragmented ones */
8492 g_assert (qtdemux->fragmented);
8496 /* pointer to the sample table */
8497 samples = stream->samples;
8499 /* starts from -1, moves to the next sample index to parse */
8500 stream->stbl_index++;
8502 /* keep track of the first and last sample to fill */
8503 first = &samples[stream->stbl_index];
8506 if (!stream->chunks_are_samples) {
8507 /* set the sample sizes */
8508 if (stream->sample_size == 0) {
8509 /* different sizes for each sample */
8510 for (cur = first; cur <= last; cur++) {
8511 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
8512 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
8513 (guint) (cur - samples), cur->size);
8516 /* samples have the same size */
8517 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
8518 for (cur = first; cur <= last; cur++)
8519 cur->size = stream->sample_size;
8523 n_samples_per_chunk = stream->n_samples_per_chunk;
8526 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
8529 if (stream->stsc_chunk_index >= stream->last_chunk
8530 || stream->stsc_chunk_index < stream->first_chunk) {
8531 stream->first_chunk =
8532 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8533 stream->samples_per_chunk =
8534 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8536 stream->stsd_sample_description_id =
8537 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
8539 /* chunk numbers are counted from 1 it seems */
8540 if (G_UNLIKELY (stream->first_chunk == 0))
8543 --stream->first_chunk;
8545 /* the last chunk of each entry is calculated by taking the first chunk
8546 * of the next entry; except if there is no next, where we fake it with
8548 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
8549 stream->last_chunk = G_MAXUINT32;
8551 stream->last_chunk =
8552 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
8553 if (G_UNLIKELY (stream->last_chunk == 0))
8556 --stream->last_chunk;
8559 GST_LOG_OBJECT (qtdemux,
8560 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
8561 "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
8562 stream->samples_per_chunk, stream->stsd_sample_description_id);
8564 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
8567 if (stream->last_chunk != G_MAXUINT32) {
8568 if (!qt_atom_parser_peek_sub (&stream->stco,
8569 stream->first_chunk * stream->co_size,
8570 (stream->last_chunk - stream->first_chunk) * stream->co_size,
8575 stream->co_chunk = stream->stco;
8576 if (!gst_byte_reader_skip (&stream->co_chunk,
8577 stream->first_chunk * stream->co_size))
8581 stream->stsc_chunk_index = stream->first_chunk;
8584 last_chunk = stream->last_chunk;
8586 if (stream->chunks_are_samples) {
8587 cur = &samples[stream->stsc_chunk_index];
8589 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8592 stream->stsc_chunk_index = j;
8597 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
8600 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
8601 "%" G_GUINT64_FORMAT, j, cur->offset);
8603 if (CUR_STREAM (stream)->samples_per_frame > 0 &&
8604 CUR_STREAM (stream)->bytes_per_frame > 0) {
8606 (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
8607 CUR_STREAM (stream)->samples_per_frame *
8608 CUR_STREAM (stream)->bytes_per_frame;
8610 cur->size = stream->samples_per_chunk;
8613 GST_DEBUG_OBJECT (qtdemux,
8614 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
8615 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
8616 stream->stco_sample_index)), cur->size);
8618 cur->timestamp = stream->stco_sample_index;
8619 cur->duration = stream->samples_per_chunk;
8620 cur->keyframe = TRUE;
8623 stream->stco_sample_index += stream->samples_per_chunk;
8625 stream->stsc_chunk_index = j;
8627 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8628 guint32 samples_per_chunk;
8629 guint64 chunk_offset;
8631 if (!stream->stsc_sample_index
8632 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
8633 &stream->chunk_offset))
8636 samples_per_chunk = stream->samples_per_chunk;
8637 chunk_offset = stream->chunk_offset;
8639 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
8640 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
8641 G_GUINT64_FORMAT " and size %d",
8642 (guint) (cur - samples), chunk_offset, cur->size);
8644 cur->offset = chunk_offset;
8645 chunk_offset += cur->size;
8648 if (G_UNLIKELY (cur > last)) {
8650 stream->stsc_sample_index = k + 1;
8651 stream->chunk_offset = chunk_offset;
8652 stream->stsc_chunk_index = j;
8656 stream->stsc_sample_index = 0;
8658 stream->stsc_chunk_index = j;
8660 stream->stsc_index++;
8663 if (stream->chunks_are_samples)
8667 guint32 n_sample_times;
8669 n_sample_times = stream->n_sample_times;
8672 for (i = stream->stts_index; i < n_sample_times; i++) {
8673 guint32 stts_samples;
8674 gint32 stts_duration;
8677 if (stream->stts_sample_index >= stream->stts_samples
8678 || !stream->stts_sample_index) {
8680 stream->stts_samples =
8681 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8682 stream->stts_duration =
8683 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8685 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
8686 i, stream->stts_samples, stream->stts_duration);
8688 stream->stts_sample_index = 0;
8691 stts_samples = stream->stts_samples;
8692 stts_duration = stream->stts_duration;
8693 stts_time = stream->stts_time;
8695 for (j = stream->stts_sample_index; j < stts_samples; j++) {
8696 GST_DEBUG_OBJECT (qtdemux,
8697 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
8698 (guint) (cur - samples), j,
8699 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
8701 cur->timestamp = stts_time;
8702 cur->duration = stts_duration;
8704 /* avoid 32-bit wrap-around,
8705 * but still mind possible 'negative' duration */
8706 stts_time += (gint64) stts_duration;
8709 if (G_UNLIKELY (cur > last)) {
8711 stream->stts_time = stts_time;
8712 stream->stts_sample_index = j + 1;
8713 if (stream->stts_sample_index >= stream->stts_samples)
8714 stream->stts_index++;
8718 stream->stts_sample_index = 0;
8719 stream->stts_time = stts_time;
8720 stream->stts_index++;
8722 /* fill up empty timestamps with the last timestamp, this can happen when
8723 * the last samples do not decode and so we don't have timestamps for them.
8724 * We however look at the last timestamp to estimate the track length so we
8725 * need something in here. */
8726 for (; cur < last; cur++) {
8727 GST_DEBUG_OBJECT (qtdemux,
8728 "fill sample %d: timestamp %" GST_TIME_FORMAT,
8729 (guint) (cur - samples),
8730 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
8731 cur->timestamp = stream->stts_time;
8737 /* sample sync, can be NULL */
8738 if (stream->stss_present == TRUE) {
8739 guint32 n_sample_syncs;
8741 n_sample_syncs = stream->n_sample_syncs;
8743 if (!n_sample_syncs) {
8744 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
8745 stream->all_keyframe = TRUE;
8747 for (i = stream->stss_index; i < n_sample_syncs; i++) {
8748 /* note that the first sample is index 1, not 0 */
8751 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
8753 if (G_LIKELY (index > 0 && index <= n_samples)) {
8755 samples[index].keyframe = TRUE;
8756 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8757 /* and exit if we have enough samples */
8758 if (G_UNLIKELY (index >= n)) {
8765 stream->stss_index = i;
8768 /* stps marks partial sync frames like open GOP I-Frames */
8769 if (stream->stps_present == TRUE) {
8770 guint32 n_sample_partial_syncs;
8772 n_sample_partial_syncs = stream->n_sample_partial_syncs;
8774 /* if there are no entries, the stss table contains the real
8776 if (n_sample_partial_syncs) {
8777 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
8778 /* note that the first sample is index 1, not 0 */
8781 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
8783 if (G_LIKELY (index > 0 && index <= n_samples)) {
8785 samples[index].keyframe = TRUE;
8786 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8787 /* and exit if we have enough samples */
8788 if (G_UNLIKELY (index >= n)) {
8795 stream->stps_index = i;
8799 /* no stss, all samples are keyframes */
8800 stream->all_keyframe = TRUE;
8801 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
8806 /* composition time to sample */
8807 if (stream->ctts_present == TRUE) {
8808 guint32 n_composition_times;
8810 gint32 ctts_soffset;
8812 /* Fill in the pts_offsets */
8814 n_composition_times = stream->n_composition_times;
8816 for (i = stream->ctts_index; i < n_composition_times; i++) {
8817 if (stream->ctts_sample_index >= stream->ctts_count
8818 || !stream->ctts_sample_index) {
8819 stream->ctts_count =
8820 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
8821 stream->ctts_soffset =
8822 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8823 stream->ctts_sample_index = 0;
8826 ctts_count = stream->ctts_count;
8827 ctts_soffset = stream->ctts_soffset;
8829 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
8830 cur->pts_offset = ctts_soffset;
8833 if (G_UNLIKELY (cur > last)) {
8835 stream->ctts_sample_index = j + 1;
8839 stream->ctts_sample_index = 0;
8840 stream->ctts_index++;
8844 stream->stbl_index = n;
8845 /* if index has been completely parsed, free data that is no-longer needed */
8846 if (n + 1 == stream->n_samples) {
8847 gst_qtdemux_stbl_free (stream);
8848 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
8849 if (qtdemux->pullbased) {
8850 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
8851 while (n + 1 == stream->n_samples)
8852 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
8856 GST_OBJECT_UNLOCK (qtdemux);
8863 GST_LOG_OBJECT (qtdemux,
8864 "Tried to parse up to sample %u but this sample has already been parsed",
8866 /* if fragmented, there may be more */
8867 if (qtdemux->fragmented && n == stream->stbl_index)
8869 GST_OBJECT_UNLOCK (qtdemux);
8875 GST_LOG_OBJECT (qtdemux,
8876 "Tried to parse up to sample %u but there are only %u samples", n + 1,
8878 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8879 (_("This file is corrupt and cannot be played.")), (NULL));
8884 GST_OBJECT_UNLOCK (qtdemux);
8885 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8886 (_("This file is corrupt and cannot be played.")), (NULL));
8891 /* collect all segment info for @stream.
8894 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
8898 /* accept edts if they contain gaps at start and there is only
8899 * one media segment */
8900 gboolean allow_pushbased_edts = TRUE;
8901 gint media_segments_count = 0;
8903 /* parse and prepare segment info from the edit list */
8904 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
8905 stream->n_segments = 0;
8906 stream->segments = NULL;
8907 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
8910 gint i, count, entry_size;
8913 const guint8 *buffer;
8917 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
8918 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
8921 buffer = elst->data;
8923 size = QT_UINT32 (buffer);
8924 /* version, flags, n_segments */
8926 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
8929 version = QT_UINT8 (buffer + 8);
8930 entry_size = (version == 1) ? 20 : 12;
8932 n_segments = QT_UINT32 (buffer + 12);
8934 if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
8935 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
8939 /* we might allocate a bit too much, at least allocate 1 segment */
8940 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
8942 /* segments always start from 0 */
8947 for (i = 0; i < n_segments; i++) {
8950 gboolean time_valid = TRUE;
8951 QtDemuxSegment *segment;
8953 GstClockTime media_start = GST_CLOCK_TIME_NONE;
8956 media_time = QT_UINT64 (buffer + 8);
8957 duration = QT_UINT64 (buffer);
8958 if (media_time == G_MAXUINT64)
8961 media_time = QT_UINT32 (buffer + 4);
8962 duration = QT_UINT32 (buffer);
8963 if (media_time == G_MAXUINT32)
8968 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
8970 segment = &stream->segments[count++];
8972 /* time and duration expressed in global timescale */
8973 segment->time = stime;
8974 /* add non scaled values so we don't cause roundoff errors */
8975 if (duration || media_start == GST_CLOCK_TIME_NONE) {
8977 stime = QTTIME_TO_GSTTIME (qtdemux, time);
8978 segment->duration = stime - segment->time;
8980 /* zero duration does not imply media_start == media_stop
8981 * but, only specify media_start.*/
8982 stime = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
8983 if (GST_CLOCK_TIME_IS_VALID (stime) && time_valid
8984 && stime >= media_start) {
8985 segment->duration = stime - media_start;
8987 segment->duration = GST_CLOCK_TIME_NONE;
8990 segment->stop_time = stime;
8992 segment->trak_media_start = media_time;
8993 /* media_time expressed in stream timescale */
8995 segment->media_start = media_start;
8996 segment->media_stop = segment->media_start + segment->duration;
8997 media_segments_count++;
8999 segment->media_start = GST_CLOCK_TIME_NONE;
9000 segment->media_stop = GST_CLOCK_TIME_NONE;
9002 rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
9004 if (rate_int <= 1) {
9005 /* 0 is not allowed, some programs write 1 instead of the floating point
9007 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
9011 segment->rate = rate_int / 65536.0;
9014 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
9015 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
9016 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
9017 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
9018 i, GST_TIME_ARGS (segment->time),
9019 GST_TIME_ARGS (segment->duration),
9020 GST_TIME_ARGS (segment->media_start), media_time,
9021 GST_TIME_ARGS (segment->media_stop),
9022 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
9024 if (segment->stop_time > qtdemux->segment.stop) {
9025 GST_WARNING_OBJECT (qtdemux, "Segment %d "
9026 " extends to %" GST_TIME_FORMAT
9027 " past the end of the file duration %" GST_TIME_FORMAT
9028 " it will be truncated", i, GST_TIME_ARGS (segment->stop_time),
9029 GST_TIME_ARGS (qtdemux->segment.stop));
9030 qtdemux->segment.stop = segment->stop_time;
9033 buffer += entry_size;
9035 GST_DEBUG_OBJECT (qtdemux, "found %d segments", count);
9036 stream->n_segments = count;
9037 if (media_segments_count != 1)
9038 allow_pushbased_edts = FALSE;
9042 /* push based does not handle segments, so act accordingly here,
9043 * and warn if applicable */
9044 if (!qtdemux->pullbased && !allow_pushbased_edts) {
9045 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
9046 /* remove and use default one below, we stream like it anyway */
9047 g_free (stream->segments);
9048 stream->segments = NULL;
9049 stream->n_segments = 0;
9052 /* no segments, create one to play the complete trak */
9053 if (stream->n_segments == 0) {
9054 GstClockTime stream_duration =
9055 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
9057 if (stream->segments == NULL)
9058 stream->segments = g_new (QtDemuxSegment, 1);
9060 /* represent unknown our way */
9061 if (stream_duration == 0)
9062 stream_duration = GST_CLOCK_TIME_NONE;
9064 stream->segments[0].time = 0;
9065 stream->segments[0].stop_time = stream_duration;
9066 stream->segments[0].duration = stream_duration;
9067 stream->segments[0].media_start = 0;
9068 stream->segments[0].media_stop = stream_duration;
9069 stream->segments[0].rate = 1.0;
9070 stream->segments[0].trak_media_start = 0;
9072 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
9073 GST_TIME_ARGS (stream_duration));
9074 stream->n_segments = 1;
9075 stream->dummy_segment = TRUE;
9077 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
9083 * Parses the stsd atom of a svq3 trak looking for
9084 * the SMI and gama atoms.
9087 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
9088 const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
9090 const guint8 *_gamma = NULL;
9091 GstBuffer *_seqh = NULL;
9092 const guint8 *stsd_data = stsd_entry_data;
9093 guint32 length = QT_UINT32 (stsd_data);
9097 GST_WARNING_OBJECT (qtdemux, "stsd too short");
9103 version = QT_UINT16 (stsd_data);
9108 while (length > 8) {
9109 guint32 fourcc, size;
9111 size = QT_UINT32 (stsd_data);
9112 fourcc = QT_FOURCC (stsd_data + 4);
9113 data = stsd_data + 8;
9116 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
9117 "svq3 atom parsing");
9126 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
9127 " for gama atom, expected 12", size);
9132 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
9134 if (_seqh != NULL) {
9135 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
9136 " found, ignoring");
9138 seqh_size = QT_UINT32 (data + 4);
9139 if (seqh_size > 0) {
9140 _seqh = gst_buffer_new_and_alloc (seqh_size);
9141 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
9148 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
9149 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
9153 if (size <= length) {
9159 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
9162 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
9163 G_GUINT16_FORMAT, version);
9174 gst_buffer_unref (_seqh);
9179 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
9186 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
9187 * atom that might contain a 'data' atom with the rtsp uri.
9188 * This case was reported in bug #597497, some info about
9189 * the hndl atom can be found in TN1195
9191 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
9192 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
9195 guint32 dref_num_entries = 0;
9196 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
9197 gst_byte_reader_skip (&dref, 4) &&
9198 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
9201 /* search dref entries for hndl atom */
9202 for (i = 0; i < dref_num_entries; i++) {
9203 guint32 size = 0, type;
9204 guint8 string_len = 0;
9205 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
9206 qt_atom_parser_get_fourcc (&dref, &type)) {
9207 if (type == FOURCC_hndl) {
9208 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
9210 /* skip data reference handle bytes and the
9211 * following pascal string and some extra 4
9212 * bytes I have no idea what are */
9213 if (!gst_byte_reader_skip (&dref, 4) ||
9214 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
9215 !gst_byte_reader_skip (&dref, string_len + 4)) {
9216 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
9220 /* iterate over the atoms to find the data atom */
9221 while (gst_byte_reader_get_remaining (&dref) >= 8) {
9225 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
9226 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
9227 if (atom_type == FOURCC_data) {
9228 const guint8 *uri_aux = NULL;
9230 /* found the data atom that might contain the rtsp uri */
9231 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
9232 "hndl atom, interpreting it as an URI");
9233 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
9235 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
9236 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
9238 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
9239 "didn't contain a rtsp address");
9241 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
9246 /* skipping to the next entry */
9247 if (!gst_byte_reader_skip (&dref, atom_size - 8))
9250 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
9257 /* skip to the next entry */
9258 if (!gst_byte_reader_skip (&dref, size - 8))
9261 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
9264 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
9270 #define AMR_NB_ALL_MODES 0x81ff
9271 #define AMR_WB_ALL_MODES 0x83ff
9273 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
9275 /* The 'damr' atom is of the form:
9277 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
9278 * 32 b 8 b 16 b 8 b 8 b
9280 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
9281 * represents the highest mode used in the stream (and thus the maximum
9282 * bitrate), with a couple of special cases as seen below.
9285 /* Map of frame type ID -> bitrate */
9286 static const guint nb_bitrates[] = {
9287 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
9289 static const guint wb_bitrates[] = {
9290 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
9296 gst_buffer_map (buf, &map, GST_MAP_READ);
9298 if (map.size != 0x11) {
9299 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
9303 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
9304 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
9305 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
9309 mode_set = QT_UINT16 (map.data + 13);
9311 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
9312 max_mode = 7 + (wb ? 1 : 0);
9314 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
9315 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
9317 if (max_mode == -1) {
9318 GST_DEBUG ("No mode indication was found (mode set) = %x",
9323 gst_buffer_unmap (buf, &map);
9324 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
9327 gst_buffer_unmap (buf, &map);
9332 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
9333 GstByteReader * reader, guint32 * matrix, const gchar * atom)
9336 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
9342 if (gst_byte_reader_get_remaining (reader) < 36)
9345 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
9346 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
9347 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
9348 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
9349 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
9350 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
9351 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
9352 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
9353 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
9355 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
9356 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
9357 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
9359 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
9360 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
9362 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
9363 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
9370 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
9371 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
9378 * This macro will only compare value abdegh, it expects cfi to have already
9381 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
9382 (m)[3] == (d << 16) && (m)[4] == (e << 16))
9384 /* only handle the cases where the last column has standard values */
9385 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
9386 const gchar *rotation_tag = NULL;
9388 /* no rotation needed */
9389 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
9391 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
9392 rotation_tag = "rotate-90";
9393 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
9394 rotation_tag = "rotate-180";
9395 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
9396 rotation_tag = "rotate-270";
9398 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9401 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
9403 if (rotation_tag != NULL) {
9404 if (*taglist == NULL)
9405 *taglist = gst_tag_list_new_empty ();
9406 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
9407 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
9410 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9414 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
9415 * protected streams (sinf, frma, schm and schi); if the protection scheme is
9416 * Common Encryption (cenc), the function will also parse the tenc box (defined
9417 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
9418 * (typically an enc[v|a|t|s] sample entry); the function will set
9419 * @original_fmt to the fourcc of the original unencrypted stream format.
9420 * Returns TRUE if successful; FALSE otherwise. */
9422 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
9423 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
9430 g_return_val_if_fail (qtdemux != NULL, FALSE);
9431 g_return_val_if_fail (stream != NULL, FALSE);
9432 g_return_val_if_fail (container != NULL, FALSE);
9433 g_return_val_if_fail (original_fmt != NULL, FALSE);
9435 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
9436 if (G_UNLIKELY (!sinf)) {
9437 if (stream->protection_scheme_type == FOURCC_cenc) {
9438 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
9439 "mandatory for Common Encryption");
9445 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
9446 if (G_UNLIKELY (!frma)) {
9447 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
9451 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
9452 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
9453 GST_FOURCC_ARGS (*original_fmt));
9455 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
9457 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
9460 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
9461 stream->protection_scheme_version =
9462 QT_UINT32 ((const guint8 *) schm->data + 16);
9464 GST_DEBUG_OBJECT (qtdemux,
9465 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
9466 "protection_scheme_version: %#010x",
9467 GST_FOURCC_ARGS (stream->protection_scheme_type),
9468 stream->protection_scheme_version);
9470 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
9472 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
9475 if (stream->protection_scheme_type == FOURCC_cenc) {
9476 QtDemuxCencSampleSetInfo *info;
9478 const guint8 *tenc_data;
9479 guint32 isEncrypted;
9481 const guint8 *default_kid;
9484 if (G_UNLIKELY (!stream->protection_scheme_info))
9485 stream->protection_scheme_info =
9486 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
9488 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
9490 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
9492 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
9493 "which is mandatory for Common Encryption");
9496 tenc_data = (const guint8 *) tenc->data + 12;
9497 isEncrypted = QT_UINT24 (tenc_data);
9498 iv_size = QT_UINT8 (tenc_data + 3);
9499 default_kid = (tenc_data + 4);
9500 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
9501 gst_buffer_fill (kid_buf, 0, default_kid, 16);
9502 if (info->default_properties)
9503 gst_structure_free (info->default_properties);
9504 info->default_properties =
9505 gst_structure_new ("application/x-cenc",
9506 "iv_size", G_TYPE_UINT, iv_size,
9507 "encrypted", G_TYPE_BOOLEAN, (isEncrypted == 1),
9508 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
9509 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
9510 "is_encrypted=%u, iv_size=%u", isEncrypted, iv_size);
9511 gst_buffer_unref (kid_buf);
9517 * With each track we associate a new QtDemuxStream that contains all the info
9519 * traks that do not decode to something (like strm traks) will not have a pad.
9522 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
9543 QtDemuxStream *stream = NULL;
9544 gboolean new_stream = FALSE;
9545 gchar *codec = NULL;
9546 const guint8 *stsd_data;
9547 const guint8 *stsd_entry_data;
9548 guint remaining_stsd_len;
9549 guint stsd_entry_count;
9551 guint16 lang_code; /* quicktime lang code or packed iso code */
9553 guint32 tkhd_flags = 0;
9554 guint8 tkhd_version = 0;
9555 guint32 w = 0, h = 0;
9557 guint value_size, stsd_len, len;
9561 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
9563 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
9564 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
9565 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
9568 /* pick between 64 or 32 bits */
9569 value_size = tkhd_version == 1 ? 8 : 4;
9570 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
9571 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
9574 if (!qtdemux->got_moov) {
9575 if (qtdemux_find_stream (qtdemux, track_id))
9576 goto existing_stream;
9577 stream = _create_stream ();
9578 stream->track_id = track_id;
9581 stream = qtdemux_find_stream (qtdemux, track_id);
9583 GST_WARNING_OBJECT (qtdemux, "Stream not found, going to ignore it");
9587 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
9589 /* flush samples data from this track from previous moov */
9590 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
9591 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
9593 /* need defaults for fragments */
9594 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
9596 if ((tkhd_flags & 1) == 0)
9597 stream->disabled = TRUE;
9599 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
9600 tkhd_version, tkhd_flags, stream->track_id);
9602 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
9605 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
9606 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
9607 if (qtdemux->major_brand != FOURCC_mjp2 ||
9608 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
9612 len = QT_UINT32 ((guint8 *) mdhd->data);
9613 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
9614 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
9615 if (version == 0x01000000) {
9618 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
9619 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
9620 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
9624 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
9625 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
9626 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
9629 if (lang_code < 0x400) {
9630 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
9631 } else if (lang_code == 0x7fff) {
9632 stream->lang_id[0] = 0; /* unspecified */
9634 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
9635 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
9636 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
9637 stream->lang_id[3] = 0;
9640 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
9642 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
9644 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
9645 lang_code, stream->lang_id);
9647 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
9650 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
9651 /* chapters track reference */
9652 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
9654 gsize length = GST_READ_UINT32_BE (chap->data);
9655 if (qtdemux->chapters_track_id)
9656 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
9659 qtdemux->chapters_track_id =
9660 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
9665 /* fragmented files may have bogus duration in moov */
9666 if (!qtdemux->fragmented &&
9667 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
9668 guint64 tdur1, tdur2;
9670 /* don't overflow */
9671 tdur1 = stream->timescale * (guint64) qtdemux->duration;
9672 tdur2 = qtdemux->timescale * (guint64) stream->duration;
9675 * some of those trailers, nowadays, have prologue images that are
9676 * themselves video tracks as well. I haven't really found a way to
9677 * identify those yet, except for just looking at their duration. */
9678 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
9679 GST_WARNING_OBJECT (qtdemux,
9680 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
9681 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
9682 "found, assuming preview image or something; skipping track",
9683 stream->duration, stream->timescale, qtdemux->duration,
9684 qtdemux->timescale);
9686 gst_qtdemux_stream_free (qtdemux, stream);
9691 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
9694 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
9695 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
9697 len = QT_UINT32 ((guint8 *) hdlr->data);
9699 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
9700 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
9701 GST_FOURCC_ARGS (stream->subtype));
9703 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
9706 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
9709 /*parse svmi header if existing */
9710 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
9712 len = QT_UINT32 ((guint8 *) svmi->data);
9713 version = QT_UINT32 ((guint8 *) svmi->data + 8);
9715 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
9716 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
9717 guint8 frame_type, frame_layout;
9719 /* MPEG-A stereo video */
9720 if (qtdemux->major_brand == FOURCC_ss02)
9721 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
9723 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
9724 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
9725 switch (frame_type) {
9727 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
9730 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
9733 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
9736 /* mode 3 is primary/secondary view sequence, ie
9737 * left/right views in separate tracks. See section 7.2
9738 * of ISO/IEC 23000-11:2009 */
9739 GST_FIXME_OBJECT (qtdemux,
9740 "Implement stereo video in separate streams");
9743 if ((frame_layout & 0x1) == 0)
9744 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
9746 GST_LOG_OBJECT (qtdemux,
9747 "StereoVideo: composition type: %u, is_left_first: %u",
9748 frame_type, frame_layout);
9749 stream->multiview_mode = mode;
9750 stream->multiview_flags = flags;
9754 /* parse rest of tkhd */
9755 if (stream->subtype == FOURCC_vide) {
9758 /* version 1 uses some 64-bit ints */
9759 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
9762 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
9765 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
9766 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
9769 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
9770 &stream->stream_tags);
9774 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
9776 stsd_data = (const guint8 *) stsd->data;
9778 /* stsd should at least have one entry */
9779 stsd_len = QT_UINT32 (stsd_data);
9780 if (stsd_len < 24) {
9781 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
9782 if (stream->subtype == FOURCC_vivo) {
9784 gst_qtdemux_stream_free (qtdemux, stream);
9791 stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
9792 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
9793 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
9794 GST_LOG_OBJECT (qtdemux, "stsd entry count: %u", stsd_entry_count);
9796 stsd_entry_data = stsd_data + 16;
9797 remaining_stsd_len = stsd_len - 16;
9798 for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
9799 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
9801 /* and that entry should fit within stsd */
9802 len = QT_UINT32 (stsd_entry_data);
9803 if (len > remaining_stsd_len)
9806 entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
9807 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
9808 GST_FOURCC_ARGS (entry->fourcc));
9809 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
9811 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
9812 goto error_encrypted;
9814 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
9815 /* FIXME this looks wrong, there might be multiple children
9816 * with the same type */
9817 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
9818 stream->protected = TRUE;
9819 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
9820 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
9823 if (stream->subtype == FOURCC_vide) {
9825 gint depth, palette_size, palette_count;
9826 guint32 *palette_data = NULL;
9828 entry->sampled = TRUE;
9830 stream->display_width = w >> 16;
9831 stream->display_height = h >> 16;
9834 if (len < 86) /* TODO verify */
9837 entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
9838 entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
9839 entry->fps_n = 0; /* this is filled in later */
9840 entry->fps_d = 0; /* this is filled in later */
9841 entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
9842 entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
9844 /* if color_table_id is 0, ctab atom must follow; however some files
9845 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
9846 * if color table is not present we'll correct the value */
9847 if (entry->color_table_id == 0 &&
9849 || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
9850 entry->color_table_id = -1;
9853 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
9854 entry->width, entry->height, entry->bits_per_sample,
9855 entry->color_table_id);
9857 depth = entry->bits_per_sample;
9859 /* more than 32 bits means grayscale */
9860 gray = (depth > 32);
9861 /* low 32 bits specify the depth */
9864 /* different number of palette entries is determined by depth. */
9866 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
9867 palette_count = (1 << depth);
9868 palette_size = palette_count * 4;
9870 if (entry->color_table_id) {
9871 switch (palette_count) {
9875 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
9878 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
9883 g_memdup (ff_qt_grayscale_palette_16, palette_size);
9885 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
9890 g_memdup (ff_qt_grayscale_palette_256, palette_size);
9892 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
9895 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
9896 (_("The video in this file might not play correctly.")),
9897 ("unsupported palette depth %d", depth));
9901 gint i, j, start, end;
9907 start = QT_UINT32 (stsd_entry_data + offset + 70);
9908 palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
9909 end = QT_UINT16 (stsd_entry_data + offset + 76);
9911 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
9912 start, end, palette_count);
9919 if (len < 94 + (end - start) * 8)
9922 /* palette is always the same size */
9923 palette_data = g_malloc0 (256 * 4);
9924 palette_size = 256 * 4;
9926 for (j = 0, i = start; i <= end; j++, i++) {
9929 a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
9930 r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
9931 g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
9932 b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
9934 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
9935 (g & 0xff00) | (b >> 8);
9940 gst_caps_unref (entry->caps);
9943 qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
9945 if (G_UNLIKELY (!entry->caps)) {
9946 g_free (palette_data);
9947 goto unknown_stream;
9951 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
9952 GST_TAG_VIDEO_CODEC, codec, NULL);
9960 if (entry->rgb8_palette)
9961 gst_memory_unref (entry->rgb8_palette);
9962 entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
9963 palette_data, palette_size, 0, palette_size, palette_data, g_free);
9965 s = gst_caps_get_structure (entry->caps, 0);
9967 /* non-raw video has a palette_data property. raw video has the palette as
9968 * an extra plane that we append to the output buffers before we push
9970 if (!gst_structure_has_name (s, "video/x-raw")) {
9973 palette = gst_buffer_new ();
9974 gst_buffer_append_memory (palette, entry->rgb8_palette);
9975 entry->rgb8_palette = NULL;
9977 gst_caps_set_simple (entry->caps, "palette_data",
9978 GST_TYPE_BUFFER, palette, NULL);
9979 gst_buffer_unref (palette);
9981 } else if (palette_count != 0) {
9982 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
9983 (NULL), ("Unsupported palette depth %d", depth));
9986 GST_LOG_OBJECT (qtdemux, "frame count: %u",
9987 QT_UINT16 (stsd_entry_data + offset + 32));
9993 /* pick 'the' stsd child */
9994 mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
9995 if (!stream->protected) {
9996 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
10000 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) {
10006 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
10007 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
10008 colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
10009 fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
10013 const guint8 *pasp_data = (const guint8 *) pasp->data;
10014 gint len = QT_UINT32 (pasp_data);
10017 CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
10018 CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
10020 CUR_STREAM (stream)->par_w = 0;
10021 CUR_STREAM (stream)->par_h = 0;
10024 CUR_STREAM (stream)->par_w = 0;
10025 CUR_STREAM (stream)->par_h = 0;
10029 const guint8 *fiel_data = (const guint8 *) fiel->data;
10030 gint len = QT_UINT32 (fiel_data);
10033 CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
10034 CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
10039 const guint8 *colr_data = (const guint8 *) colr->data;
10040 gint len = QT_UINT32 (colr_data);
10042 if (len == 19 || len == 18) {
10043 guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
10045 if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
10046 guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
10047 guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
10048 guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
10049 gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
10051 switch (primaries) {
10053 CUR_STREAM (stream)->colorimetry.primaries =
10054 GST_VIDEO_COLOR_PRIMARIES_BT709;
10057 CUR_STREAM (stream)->colorimetry.primaries =
10058 GST_VIDEO_COLOR_PRIMARIES_BT470BG;
10061 CUR_STREAM (stream)->colorimetry.primaries =
10062 GST_VIDEO_COLOR_PRIMARIES_SMPTE170M;
10065 CUR_STREAM (stream)->colorimetry.primaries =
10066 GST_VIDEO_COLOR_PRIMARIES_BT2020;
10072 switch (transfer_function) {
10074 CUR_STREAM (stream)->colorimetry.transfer =
10075 GST_VIDEO_TRANSFER_BT709;
10078 CUR_STREAM (stream)->colorimetry.transfer =
10079 GST_VIDEO_TRANSFER_SMPTE240M;
10087 CUR_STREAM (stream)->colorimetry.matrix =
10088 GST_VIDEO_COLOR_MATRIX_BT709;
10091 CUR_STREAM (stream)->colorimetry.matrix =
10092 GST_VIDEO_COLOR_MATRIX_BT601;
10095 CUR_STREAM (stream)->colorimetry.matrix =
10096 GST_VIDEO_COLOR_MATRIX_SMPTE240M;
10099 CUR_STREAM (stream)->colorimetry.matrix =
10100 GST_VIDEO_COLOR_MATRIX_BT2020;
10106 CUR_STREAM (stream)->colorimetry.range =
10107 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
10108 GST_VIDEO_COLOR_RANGE_16_235;
10110 GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
10113 GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
10118 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
10119 stream->stream_tags);
10126 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10127 const guint8 *avc_data = stsd_entry_data + 0x56;
10130 while (len >= 0x8) {
10133 if (QT_UINT32 (avc_data) <= len)
10134 size = QT_UINT32 (avc_data) - 0x8;
10139 /* No real data, so break out */
10142 switch (QT_FOURCC (avc_data + 0x4)) {
10145 /* parse, if found */
10148 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
10150 /* First 4 bytes are the length of the atom, the next 4 bytes
10151 * are the fourcc, the next 1 byte is the version, and the
10152 * subsequent bytes are profile_tier_level structure like data. */
10153 gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
10154 avc_data + 8 + 1, size - 1);
10155 buf = gst_buffer_new_and_alloc (size);
10156 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
10157 gst_caps_set_simple (entry->caps,
10158 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10159 gst_buffer_unref (buf);
10167 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
10169 /* First 4 bytes are the length of the atom, the next 4 bytes
10170 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
10171 * next 1 byte is the version, and the
10172 * subsequent bytes are sequence parameter set like data. */
10174 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
10176 gst_codec_utils_h264_caps_set_level_and_profile
10177 (entry->caps, avc_data + 8 + 40 + 1, size - 1);
10179 buf = gst_buffer_new_and_alloc (size);
10180 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
10181 gst_caps_set_simple (entry->caps,
10182 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10183 gst_buffer_unref (buf);
10189 guint avg_bitrate, max_bitrate;
10191 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
10195 max_bitrate = QT_UINT32 (avc_data + 0xc);
10196 avg_bitrate = QT_UINT32 (avc_data + 0x10);
10198 if (!max_bitrate && !avg_bitrate)
10201 /* Some muxers seem to swap the average and maximum bitrates
10202 * (I'm looking at you, YouTube), so we swap for sanity. */
10203 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
10204 guint temp = avg_bitrate;
10206 avg_bitrate = max_bitrate;
10207 max_bitrate = temp;
10210 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
10211 gst_tag_list_add (stream->stream_tags,
10212 GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
10213 max_bitrate, NULL);
10215 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
10216 gst_tag_list_add (stream->stream_tags,
10217 GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
10229 avc_data += size + 8;
10238 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10239 const guint8 *hevc_data = stsd_entry_data + 0x56;
10242 while (len >= 0x8) {
10245 if (QT_UINT32 (hevc_data) <= len)
10246 size = QT_UINT32 (hevc_data) - 0x8;
10251 /* No real data, so break out */
10254 switch (QT_FOURCC (hevc_data + 0x4)) {
10257 /* parse, if found */
10260 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
10262 /* First 4 bytes are the length of the atom, the next 4 bytes
10263 * are the fourcc, the next 1 byte is the version, and the
10264 * subsequent bytes are sequence parameter set like data. */
10265 gst_codec_utils_h265_caps_set_level_tier_and_profile
10266 (entry->caps, hevc_data + 8 + 1, size - 1);
10268 buf = gst_buffer_new_and_alloc (size);
10269 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
10270 gst_caps_set_simple (entry->caps,
10271 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10272 gst_buffer_unref (buf);
10279 hevc_data += size + 8;
10292 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
10293 GST_FOURCC_ARGS (fourcc));
10295 /* codec data might be in glbl extension atom */
10297 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
10303 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
10305 len = QT_UINT32 (data);
10308 buf = gst_buffer_new_and_alloc (len);
10309 gst_buffer_fill (buf, 0, data + 8, len);
10310 gst_caps_set_simple (entry->caps,
10311 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10312 gst_buffer_unref (buf);
10319 /* see annex I of the jpeg2000 spec */
10320 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
10321 const guint8 *data;
10322 const gchar *colorspace = NULL;
10324 guint32 ncomp_map = 0;
10325 gint32 *comp_map = NULL;
10326 guint32 nchan_def = 0;
10327 gint32 *chan_def = NULL;
10329 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
10330 /* some required atoms */
10331 mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10334 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
10338 /* number of components; redundant with info in codestream, but useful
10340 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
10341 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
10343 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
10345 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
10348 GST_DEBUG_OBJECT (qtdemux, "found colr");
10349 /* extract colour space info */
10350 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
10351 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
10353 colorspace = "sRGB";
10356 colorspace = "GRAY";
10359 colorspace = "sYUV";
10367 /* colr is required, and only values 16, 17, and 18 are specified,
10368 so error if we have no colorspace */
10371 /* extract component mapping */
10372 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
10374 guint32 cmap_len = 0;
10376 cmap_len = QT_UINT32 (cmap->data);
10377 if (cmap_len >= 8) {
10378 /* normal box, subtract off header */
10380 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
10381 if (cmap_len % 4 == 0) {
10382 ncomp_map = (cmap_len / 4);
10383 comp_map = g_new0 (gint32, ncomp_map);
10384 for (i = 0; i < ncomp_map; i++) {
10387 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
10388 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
10389 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
10390 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
10395 /* extract channel definitions */
10396 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
10398 guint32 cdef_len = 0;
10400 cdef_len = QT_UINT32 (cdef->data);
10401 if (cdef_len >= 10) {
10402 /* normal box, subtract off header and len */
10404 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
10405 if (cdef_len % 6 == 0) {
10406 nchan_def = (cdef_len / 6);
10407 chan_def = g_new0 (gint32, nchan_def);
10408 for (i = 0; i < nchan_def; i++)
10410 for (i = 0; i < nchan_def; i++) {
10411 guint16 cn, typ, asoc;
10412 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
10413 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
10414 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
10415 if (cn < nchan_def) {
10418 chan_def[cn] = asoc;
10421 chan_def[cn] = 0; /* alpha */
10424 chan_def[cn] = -typ;
10432 gst_caps_set_simple (entry->caps,
10433 "num-components", G_TYPE_INT, ncomp, NULL);
10434 gst_caps_set_simple (entry->caps,
10435 "colorspace", G_TYPE_STRING, colorspace, NULL);
10438 GValue arr = { 0, };
10439 GValue elt = { 0, };
10441 g_value_init (&arr, GST_TYPE_ARRAY);
10442 g_value_init (&elt, G_TYPE_INT);
10443 for (i = 0; i < ncomp_map; i++) {
10444 g_value_set_int (&elt, comp_map[i]);
10445 gst_value_array_append_value (&arr, &elt);
10447 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
10448 "component-map", &arr);
10449 g_value_unset (&elt);
10450 g_value_unset (&arr);
10455 GValue arr = { 0, };
10456 GValue elt = { 0, };
10458 g_value_init (&arr, GST_TYPE_ARRAY);
10459 g_value_init (&elt, G_TYPE_INT);
10460 for (i = 0; i < nchan_def; i++) {
10461 g_value_set_int (&elt, chan_def[i]);
10462 gst_value_array_append_value (&arr, &elt);
10464 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
10465 "channel-definitions", &arr);
10466 g_value_unset (&elt);
10467 g_value_unset (&arr);
10471 /* some optional atoms */
10472 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
10473 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
10475 /* indicate possible fields in caps */
10477 data = (guint8 *) field->data + 8;
10479 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
10480 (gint) * data, NULL);
10482 /* add codec_data if provided */
10487 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
10488 data = prefix->data;
10489 len = QT_UINT32 (data);
10492 buf = gst_buffer_new_and_alloc (len);
10493 gst_buffer_fill (buf, 0, data + 8, len);
10494 gst_caps_set_simple (entry->caps,
10495 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10496 gst_buffer_unref (buf);
10505 GstBuffer *seqh = NULL;
10506 const guint8 *gamma_data = NULL;
10507 gint len = QT_UINT32 (stsd_data); /* FIXME review - why put the whole stsd in codec data? */
10509 qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
10512 gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
10513 QT_FP32 (gamma_data), NULL);
10516 /* sorry for the bad name, but we don't know what this is, other
10517 * than its own fourcc */
10518 gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
10520 gst_buffer_unref (seqh);
10523 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
10524 buf = gst_buffer_new_and_alloc (len);
10525 gst_buffer_fill (buf, 0, stsd_data, len);
10526 gst_caps_set_simple (entry->caps,
10527 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10528 gst_buffer_unref (buf);
10533 /* https://developer.apple.com/standards/qtff-2001.pdf,
10534 * page 92, "Video Sample Description", under table 3.1 */
10537 const gint compressor_offset =
10538 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
10539 const gint min_size = compressor_offset + 32 + 2 + 2;
10542 guint16 color_table_id = 0;
10545 GST_DEBUG_OBJECT (qtdemux, "found jpeg");
10547 /* recover information on interlaced/progressive */
10548 jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
10552 len = QT_UINT32 (jpeg->data);
10553 GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
10555 if (len >= min_size) {
10556 gst_byte_reader_init (&br, jpeg->data, len);
10558 gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
10559 gst_byte_reader_get_uint16_le (&br, &color_table_id);
10560 if (color_table_id != 0) {
10561 /* the spec says there can be concatenated chunks in the data, and we want
10562 * to find one called field. Walk through them. */
10563 gint offset = min_size;
10564 while (offset + 8 < len) {
10565 guint32 size = 0, tag;
10566 ok = gst_byte_reader_get_uint32_le (&br, &size);
10567 ok &= gst_byte_reader_get_uint32_le (&br, &tag);
10568 if (!ok || size < 8) {
10569 GST_WARNING_OBJECT (qtdemux,
10570 "Failed to walk optional chunk list");
10573 GST_DEBUG_OBJECT (qtdemux,
10574 "Found optional %4.4s chunk, size %u",
10575 (const char *) &tag, size);
10576 if (tag == FOURCC_fiel) {
10577 guint8 n_fields = 0, ordering = 0;
10578 gst_byte_reader_get_uint8 (&br, &n_fields);
10579 gst_byte_reader_get_uint8 (&br, &ordering);
10580 if (n_fields == 1 || n_fields == 2) {
10581 GST_DEBUG_OBJECT (qtdemux,
10582 "Found fiel tag with %u fields, ordering %u",
10583 n_fields, ordering);
10585 gst_caps_set_simple (CUR_STREAM (stream)->caps,
10586 "interlace-mode", G_TYPE_STRING, "interleaved",
10589 GST_WARNING_OBJECT (qtdemux,
10590 "Found fiel tag with invalid fields (%u)", n_fields);
10596 GST_DEBUG_OBJECT (qtdemux,
10597 "Color table ID is 0, not trying to get interlacedness");
10600 GST_WARNING_OBJECT (qtdemux,
10601 "Length of jpeg chunk is too small, not trying to get interlacedness");
10609 gst_caps_set_simple (entry->caps,
10610 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 82),
10616 GNode *xith, *xdxt;
10618 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
10619 xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10623 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
10627 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
10628 /* collect the headers and store them in a stream list so that we can
10629 * send them out first */
10630 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
10640 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
10641 ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10644 ovc1_data = ovc1->data;
10645 ovc1_len = QT_UINT32 (ovc1_data);
10646 if (ovc1_len <= 198) {
10647 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
10650 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
10651 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
10652 gst_caps_set_simple (entry->caps,
10653 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10654 gst_buffer_unref (buf);
10659 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10660 const guint8 *vc1_data = stsd_entry_data + 0x56;
10666 if (QT_UINT32 (vc1_data) <= len)
10667 size = QT_UINT32 (vc1_data) - 8;
10672 /* No real data, so break out */
10675 switch (QT_FOURCC (vc1_data + 0x4)) {
10676 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
10680 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
10681 buf = gst_buffer_new_and_alloc (size);
10682 gst_buffer_fill (buf, 0, vc1_data + 8, size);
10683 gst_caps_set_simple (entry->caps,
10684 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10685 gst_buffer_unref (buf);
10692 vc1_data += size + 8;
10701 GST_INFO_OBJECT (qtdemux,
10702 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10703 GST_FOURCC_ARGS (fourcc), entry->caps);
10705 } else if (stream->subtype == FOURCC_soun) {
10706 int version, samplesize;
10707 guint16 compression_id;
10708 gboolean amrwb = FALSE;
10711 /* sample description entry (16) + sound sample description v0 (20) */
10715 version = QT_UINT32 (stsd_entry_data + offset);
10716 entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
10717 samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
10718 compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
10719 entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
10721 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
10722 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
10723 QT_UINT32 (stsd_entry_data + offset + 4));
10724 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
10725 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
10726 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
10727 GST_LOG_OBJECT (qtdemux, "packet size: %d",
10728 QT_UINT16 (stsd_entry_data + offset + 14));
10729 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
10731 if (compression_id == 0xfffe)
10732 entry->sampled = TRUE;
10734 /* first assume uncompressed audio */
10735 entry->bytes_per_sample = samplesize / 8;
10736 entry->samples_per_frame = entry->n_channels;
10737 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
10738 entry->samples_per_packet = entry->samples_per_frame;
10739 entry->bytes_per_packet = entry->bytes_per_sample;
10743 /* Yes, these have to be hard-coded */
10746 entry->samples_per_packet = 6;
10747 entry->bytes_per_packet = 1;
10748 entry->bytes_per_frame = 1 * entry->n_channels;
10749 entry->bytes_per_sample = 1;
10750 entry->samples_per_frame = 6 * entry->n_channels;
10755 entry->samples_per_packet = 3;
10756 entry->bytes_per_packet = 1;
10757 entry->bytes_per_frame = 1 * entry->n_channels;
10758 entry->bytes_per_sample = 1;
10759 entry->samples_per_frame = 3 * entry->n_channels;
10764 entry->samples_per_packet = 64;
10765 entry->bytes_per_packet = 34;
10766 entry->bytes_per_frame = 34 * entry->n_channels;
10767 entry->bytes_per_sample = 2;
10768 entry->samples_per_frame = 64 * entry->n_channels;
10774 entry->samples_per_packet = 1;
10775 entry->bytes_per_packet = 1;
10776 entry->bytes_per_frame = 1 * entry->n_channels;
10777 entry->bytes_per_sample = 1;
10778 entry->samples_per_frame = 1 * entry->n_channels;
10783 entry->samples_per_packet = 160;
10784 entry->bytes_per_packet = 33;
10785 entry->bytes_per_frame = 33 * entry->n_channels;
10786 entry->bytes_per_sample = 2;
10787 entry->samples_per_frame = 160 * entry->n_channels;
10794 if (version == 0x00010000) {
10795 /* sample description entry (16) + sound sample description v1 (20+16) */
10806 /* only parse extra decoding config for non-pcm audio */
10807 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
10808 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
10809 entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
10810 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
10812 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
10813 entry->samples_per_packet);
10814 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
10815 entry->bytes_per_packet);
10816 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
10817 entry->bytes_per_frame);
10818 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
10819 entry->bytes_per_sample);
10821 if (!entry->sampled && entry->bytes_per_packet) {
10822 entry->samples_per_frame = (entry->bytes_per_frame /
10823 entry->bytes_per_packet) * entry->samples_per_packet;
10824 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
10825 entry->samples_per_frame);
10830 } else if (version == 0x00020000) {
10837 /* sample description entry (16) + sound sample description v2 (56) */
10841 qtfp.val = QT_UINT64 (stsd_entry_data + offset + 4);
10842 entry->rate = qtfp.fp;
10843 entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
10845 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
10846 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
10847 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
10848 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
10849 QT_UINT32 (stsd_entry_data + offset + 20));
10850 GST_LOG_OBJECT (qtdemux, "format flags: %X",
10851 QT_UINT32 (stsd_entry_data + offset + 24));
10852 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
10853 QT_UINT32 (stsd_entry_data + offset + 28));
10854 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
10855 QT_UINT32 (stsd_entry_data + offset + 32));
10856 } else if (version != 0x00000) {
10857 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
10862 gst_caps_unref (entry->caps);
10864 entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
10865 stsd_entry_data + 32, len - 16, &codec);
10873 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
10875 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
10877 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
10879 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
10882 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
10883 gst_caps_set_simple (entry->caps,
10884 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE",
10891 const guint8 *owma_data;
10892 const gchar *codec_name = NULL;
10896 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
10897 /* FIXME this should also be gst_riff_strf_auds,
10898 * but the latter one is actually missing bits-per-sample :( */
10903 gint32 nSamplesPerSec;
10904 gint32 nAvgBytesPerSec;
10905 gint16 nBlockAlign;
10906 gint16 wBitsPerSample;
10909 WAVEFORMATEX *wfex;
10911 GST_DEBUG_OBJECT (qtdemux, "parse owma");
10912 owma_data = stsd_entry_data;
10913 owma_len = QT_UINT32 (owma_data);
10914 if (owma_len <= 54) {
10915 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
10918 wfex = (WAVEFORMATEX *) (owma_data + 36);
10919 buf = gst_buffer_new_and_alloc (owma_len - 54);
10920 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
10921 if (wfex->wFormatTag == 0x0161) {
10922 codec_name = "Windows Media Audio";
10924 } else if (wfex->wFormatTag == 0x0162) {
10925 codec_name = "Windows Media Audio 9 Pro";
10927 } else if (wfex->wFormatTag == 0x0163) {
10928 codec_name = "Windows Media Audio 9 Lossless";
10929 /* is that correct? gstffmpegcodecmap.c is missing it, but
10930 * fluendo codec seems to support it */
10934 gst_caps_set_simple (entry->caps,
10935 "codec_data", GST_TYPE_BUFFER, buf,
10936 "wmaversion", G_TYPE_INT, version,
10937 "block_align", G_TYPE_INT,
10938 GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
10939 GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
10940 GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
10941 GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
10942 gst_buffer_unref (buf);
10946 codec = g_strdup (codec_name);
10952 gint len = QT_UINT32 (stsd_entry_data) - offset;
10953 const guint8 *wfex_data = stsd_entry_data + offset;
10954 const gchar *codec_name = NULL;
10956 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
10957 /* FIXME this should also be gst_riff_strf_auds,
10958 * but the latter one is actually missing bits-per-sample :( */
10963 gint32 nSamplesPerSec;
10964 gint32 nAvgBytesPerSec;
10965 gint16 nBlockAlign;
10966 gint16 wBitsPerSample;
10971 /* FIXME: unify with similar wavformatex parsing code above */
10972 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
10978 if (QT_UINT32 (wfex_data) <= len)
10979 size = QT_UINT32 (wfex_data) - 8;
10984 /* No real data, so break out */
10987 switch (QT_FOURCC (wfex_data + 4)) {
10988 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
10990 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
10995 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
10996 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
10997 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
10998 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
10999 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
11000 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
11001 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
11003 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
11004 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
11005 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
11006 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
11007 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
11008 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
11010 if (wfex.wFormatTag == 0x0161) {
11011 codec_name = "Windows Media Audio";
11013 } else if (wfex.wFormatTag == 0x0162) {
11014 codec_name = "Windows Media Audio 9 Pro";
11016 } else if (wfex.wFormatTag == 0x0163) {
11017 codec_name = "Windows Media Audio 9 Lossless";
11018 /* is that correct? gstffmpegcodecmap.c is missing it, but
11019 * fluendo codec seems to support it */
11023 gst_caps_set_simple (entry->caps,
11024 "wmaversion", G_TYPE_INT, version,
11025 "block_align", G_TYPE_INT, wfex.nBlockAlign,
11026 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
11027 "width", G_TYPE_INT, wfex.wBitsPerSample,
11028 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
11030 if (size > wfex.cbSize) {
11033 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
11034 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
11035 size - wfex.cbSize);
11036 gst_caps_set_simple (entry->caps,
11037 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11038 gst_buffer_unref (buf);
11040 GST_WARNING_OBJECT (qtdemux, "no codec data");
11045 codec = g_strdup (codec_name);
11053 wfex_data += size + 8;
11059 const guint8 *opus_data;
11060 guint8 *channel_mapping = NULL;
11063 guint8 channel_mapping_family;
11064 guint8 stream_count;
11065 guint8 coupled_count;
11068 opus_data = stsd_entry_data;
11070 channels = GST_READ_UINT8 (opus_data + 45);
11071 rate = GST_READ_UINT32_LE (opus_data + 48);
11072 channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
11073 stream_count = GST_READ_UINT8 (opus_data + 55);
11074 coupled_count = GST_READ_UINT8 (opus_data + 56);
11076 if (channels > 0) {
11077 channel_mapping = g_malloc (channels * sizeof (guint8));
11078 for (i = 0; i < channels; i++)
11079 channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
11082 entry->caps = gst_codec_utils_opus_create_caps (rate, channels,
11083 channel_mapping_family, stream_count, coupled_count,
11095 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11096 GST_TAG_AUDIO_CODEC, codec, NULL);
11100 /* some bitrate info may have ended up in caps */
11101 s = gst_caps_get_structure (entry->caps, 0);
11102 gst_structure_get_int (s, "bitrate", &bitrate);
11104 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11105 GST_TAG_BITRATE, bitrate, NULL);
11108 mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11109 if (!stream->protected) {
11111 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) {
11115 if (stream->protected && fourcc == FOURCC_mp4a) {
11116 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) {
11120 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_mp4a) {
11128 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
11130 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
11132 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
11136 /* If the fourcc's bottom 16 bits gives 'sm', then the top
11137 16 bits is a byte-swapped wave-style codec identifier,
11138 and we can find a WAVE header internally to a 'wave' atom here.
11139 This can more clearly be thought of as 'ms' as the top 16 bits, and a
11140 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
11143 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
11144 if (len < offset + 20) {
11145 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
11147 guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
11148 const guint8 *data = stsd_entry_data + offset + 16;
11150 GNode *waveheadernode;
11152 wavenode = g_node_new ((guint8 *) data);
11153 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
11154 const guint8 *waveheader;
11157 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
11158 if (waveheadernode) {
11159 waveheader = (const guint8 *) waveheadernode->data;
11160 headerlen = QT_UINT32 (waveheader);
11162 if (headerlen > 8) {
11163 gst_riff_strf_auds *header = NULL;
11164 GstBuffer *headerbuf;
11170 headerbuf = gst_buffer_new_and_alloc (headerlen);
11171 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
11173 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
11174 headerbuf, &header, &extra)) {
11175 gst_caps_unref (entry->caps);
11176 /* FIXME: Need to do something with the channel reorder map */
11178 gst_riff_create_audio_caps (header->format, NULL, header,
11179 extra, NULL, NULL, NULL);
11182 gst_buffer_unref (extra);
11187 GST_DEBUG ("Didn't find waveheadernode for this codec");
11189 g_node_destroy (wavenode);
11192 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11193 stream->stream_tags);
11197 /* FIXME: what is in the chunk? */
11200 gint len = QT_UINT32 (stsd_data);
11202 /* seems to be always = 116 = 0x74 */
11208 gint len = QT_UINT32 (stsd_entry_data);
11211 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
11213 gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
11214 gst_caps_set_simple (entry->caps,
11215 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11216 gst_buffer_unref (buf);
11218 gst_caps_set_simple (entry->caps,
11219 "samplesize", G_TYPE_INT, samplesize, NULL);
11224 GNode *alac, *wave = NULL;
11226 /* apparently, m4a has this atom appended directly in the stsd entry,
11227 * while mov has it in a wave atom */
11228 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
11230 /* alac now refers to stsd entry atom */
11231 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
11233 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
11235 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
11238 const guint8 *alac_data = alac->data;
11239 gint len = QT_UINT32 (alac->data);
11243 GST_DEBUG_OBJECT (qtdemux,
11244 "discarding alac atom with unexpected len %d", len);
11246 /* codec-data contains alac atom size and prefix,
11247 * ffmpeg likes it that way, not quite gst-ish though ...*/
11248 buf = gst_buffer_new_and_alloc (len);
11249 gst_buffer_fill (buf, 0, alac->data, len);
11250 gst_caps_set_simple (entry->caps,
11251 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11252 gst_buffer_unref (buf);
11254 entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
11255 entry->n_channels = QT_UINT8 (alac_data + 21);
11256 entry->rate = QT_UINT32 (alac_data + 32);
11259 gst_caps_set_simple (entry->caps,
11260 "samplesize", G_TYPE_INT, samplesize, NULL);
11265 /* The codingname of the sample entry is 'fLaC' */
11266 GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
11269 /* The 'dfLa' box is added to the sample entry to convey
11270 initializing information for the decoder. */
11271 const GNode *dfla =
11272 qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
11275 const guint32 len = QT_UINT32 (dfla->data);
11277 /* Must contain at least dfLa box header (12),
11278 * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
11280 GST_DEBUG_OBJECT (qtdemux,
11281 "discarding dfla atom with unexpected len %d", len);
11283 /* skip dfLa header to get the METADATA_BLOCKs */
11284 const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
11285 const guint32 metadata_blocks_len = len - 12;
11287 gchar *stream_marker = g_strdup ("fLaC");
11288 GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
11289 strlen (stream_marker));
11292 guint32 remainder = 0;
11293 guint32 block_size = 0;
11294 gboolean is_last = FALSE;
11296 GValue array = G_VALUE_INIT;
11297 GValue value = G_VALUE_INIT;
11299 g_value_init (&array, GST_TYPE_ARRAY);
11300 g_value_init (&value, GST_TYPE_BUFFER);
11302 gst_value_set_buffer (&value, block);
11303 gst_value_array_append_value (&array, &value);
11304 g_value_reset (&value);
11306 gst_buffer_unref (block);
11308 /* check there's at least one METADATA_BLOCK_HEADER's worth
11309 * of data, and we haven't already finished parsing */
11310 while (!is_last && ((index + 3) < metadata_blocks_len)) {
11311 remainder = metadata_blocks_len - index;
11313 /* add the METADATA_BLOCK_HEADER size to the signalled size */
11315 (metadata_blocks[index + 1] << 16) +
11316 (metadata_blocks[index + 2] << 8) +
11317 metadata_blocks[index + 3];
11319 /* be careful not to read off end of box */
11320 if (block_size > remainder) {
11324 is_last = metadata_blocks[index] >> 7;
11326 block = gst_buffer_new_and_alloc (block_size);
11328 gst_buffer_fill (block, 0, &metadata_blocks[index],
11331 gst_value_set_buffer (&value, block);
11332 gst_value_array_append_value (&array, &value);
11333 g_value_reset (&value);
11335 gst_buffer_unref (block);
11337 index += block_size;
11340 /* only append the metadata if we successfully read all of it */
11342 gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
11343 (stream)->caps, 0), "streamheader", &array);
11345 GST_WARNING_OBJECT (qtdemux,
11346 "discarding all METADATA_BLOCKs due to invalid "
11347 "block_size %d at idx %d, rem %d", block_size, index,
11351 g_value_unset (&value);
11352 g_value_unset (&array);
11354 /* The sample rate obtained from the stsd may not be accurate
11355 * since it cannot represent rates greater than 65535Hz, so
11356 * override that value with the sample rate from the
11357 * METADATA_BLOCK_STREAMINFO block */
11358 CUR_STREAM (stream)->rate =
11359 (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
11370 gint len = QT_UINT32 (stsd_entry_data);
11373 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
11376 gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
11378 /* If we have enough data, let's try to get the 'damr' atom. See
11379 * the 3GPP container spec (26.244) for more details. */
11380 if ((len - 0x34) > 8 &&
11381 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
11382 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11383 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
11386 gst_caps_set_simple (entry->caps,
11387 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11388 gst_buffer_unref (buf);
11394 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
11395 gint len = QT_UINT32 (stsd_entry_data);
11398 guint16 sound_version = QT_UINT16 (stsd_entry_data + 16);
11400 if (sound_version == 1) {
11401 guint16 channels = QT_UINT16 (stsd_entry_data + 24);
11402 guint32 time_scale = QT_UINT32 (stsd_entry_data + 30);
11403 guint8 codec_data[2];
11405 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
11407 gint sample_rate_index =
11408 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
11410 /* build AAC codec data */
11411 codec_data[0] = profile << 3;
11412 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
11413 codec_data[1] = (sample_rate_index & 0x01) << 7;
11414 codec_data[1] |= (channels & 0xF) << 3;
11416 buf = gst_buffer_new_and_alloc (2);
11417 gst_buffer_fill (buf, 0, codec_data, 2);
11418 gst_caps_set_simple (entry->caps,
11419 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11420 gst_buffer_unref (buf);
11426 GST_INFO_OBJECT (qtdemux,
11427 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11431 GST_INFO_OBJECT (qtdemux,
11432 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11433 GST_FOURCC_ARGS (fourcc), entry->caps);
11435 } else if (stream->subtype == FOURCC_strm) {
11436 if (fourcc == FOURCC_rtsp) {
11437 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
11439 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
11440 GST_FOURCC_ARGS (fourcc));
11441 goto unknown_stream;
11443 entry->sampled = TRUE;
11444 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
11445 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
11447 entry->sampled = TRUE;
11448 entry->sparse = TRUE;
11451 qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11454 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11455 GST_TAG_SUBTITLE_CODEC, codec, NULL);
11460 /* hunt for sort-of codec data */
11464 GNode *mp4s = NULL;
11465 GNode *esds = NULL;
11467 /* look for palette in a stsd->mp4s->esds sub-atom */
11468 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
11470 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
11471 if (esds == NULL) {
11473 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
11477 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11478 stream->stream_tags);
11482 GST_INFO_OBJECT (qtdemux,
11483 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11486 GST_INFO_OBJECT (qtdemux,
11487 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11488 GST_FOURCC_ARGS (fourcc), entry->caps);
11490 /* everything in 1 sample */
11491 entry->sampled = TRUE;
11494 qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11497 if (entry->caps == NULL)
11498 goto unknown_stream;
11501 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11502 GST_TAG_SUBTITLE_CODEC, codec, NULL);
11508 /* promote to sampled format */
11509 if (entry->fourcc == FOURCC_samr) {
11510 /* force mono 8000 Hz for AMR */
11511 entry->sampled = TRUE;
11512 entry->n_channels = 1;
11513 entry->rate = 8000;
11514 } else if (entry->fourcc == FOURCC_sawb) {
11515 /* force mono 16000 Hz for AMR-WB */
11516 entry->sampled = TRUE;
11517 entry->n_channels = 1;
11518 entry->rate = 16000;
11519 } else if (entry->fourcc == FOURCC_mp4a) {
11520 entry->sampled = TRUE;
11524 stsd_entry_data += len;
11525 remaining_stsd_len -= len;
11529 /* collect sample information */
11530 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
11531 goto samples_failed;
11533 if (qtdemux->fragmented) {
11536 /* need all moov samples as basis; probably not many if any at all */
11537 /* prevent moof parsing taking of at this time */
11538 offset = qtdemux->moof_offset;
11539 qtdemux->moof_offset = 0;
11540 if (stream->n_samples &&
11541 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
11542 qtdemux->moof_offset = offset;
11543 goto samples_failed;
11545 qtdemux->moof_offset = 0;
11546 /* movie duration more reliable in this case (e.g. mehd) */
11547 if (qtdemux->segment.duration &&
11548 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
11550 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
11553 /* configure segments */
11554 if (!qtdemux_parse_segments (qtdemux, stream, trak))
11555 goto segments_failed;
11557 /* add some language tag, if useful */
11558 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
11559 strcmp (stream->lang_id, "und")) {
11560 const gchar *lang_code;
11562 /* convert ISO 639-2 code to ISO 639-1 */
11563 lang_code = gst_tag_get_language_code (stream->lang_id);
11564 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11565 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
11568 /* Check for UDTA tags */
11569 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
11570 qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
11573 /* now we are ready to add the stream */
11574 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
11575 goto too_many_streams;
11577 if (!qtdemux->got_moov) {
11578 qtdemux->streams[qtdemux->n_streams] = stream;
11579 qtdemux->n_streams++;
11580 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
11588 GST_INFO_OBJECT (qtdemux, "skip disabled track");
11590 gst_qtdemux_stream_free (qtdemux, stream);
11595 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
11596 (_("This file is corrupt and cannot be played.")), (NULL));
11598 gst_qtdemux_stream_free (qtdemux, stream);
11603 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
11605 gst_qtdemux_stream_free (qtdemux, stream);
11611 /* we posted an error already */
11612 /* free stbl sub-atoms */
11613 gst_qtdemux_stbl_free (stream);
11615 gst_qtdemux_stream_free (qtdemux, stream);
11620 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
11623 gst_qtdemux_stream_free (qtdemux, stream);
11628 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
11629 GST_FOURCC_ARGS (stream->subtype));
11631 gst_qtdemux_stream_free (qtdemux, stream);
11636 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
11637 (_("This file contains too many streams. Only playing first %d"),
11638 GST_QTDEMUX_MAX_STREAMS), (NULL));
11643 /* If we can estimate the overall bitrate, and don't have information about the
11644 * stream bitrate for exactly one stream, this guesses the stream bitrate as
11645 * the overall bitrate minus the sum of the bitrates of all other streams. This
11646 * should be useful for the common case where we have one audio and one video
11647 * stream and can estimate the bitrate of one, but not the other. */
11649 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
11651 QtDemuxStream *stream = NULL;
11652 gint64 size, sys_bitrate, sum_bitrate = 0;
11653 GstClockTime duration;
11657 if (qtdemux->fragmented)
11660 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
11662 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
11664 GST_DEBUG_OBJECT (qtdemux,
11665 "Size in bytes of the stream not known - bailing");
11669 /* Subtract the header size */
11670 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
11671 size, qtdemux->header_size);
11673 if (size < qtdemux->header_size)
11676 size = size - qtdemux->header_size;
11678 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
11679 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
11683 for (i = 0; i < qtdemux->n_streams; i++) {
11684 switch (qtdemux->streams[i]->subtype) {
11687 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
11688 CUR_STREAM (qtdemux->streams[i])->caps);
11689 /* retrieve bitrate, prefer avg then max */
11691 if (qtdemux->streams[i]->stream_tags) {
11692 gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags,
11693 GST_TAG_MAXIMUM_BITRATE, &bitrate);
11694 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
11695 gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags,
11696 GST_TAG_NOMINAL_BITRATE, &bitrate);
11697 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
11698 gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags,
11699 GST_TAG_BITRATE, &bitrate);
11700 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
11703 sum_bitrate += bitrate;
11706 GST_DEBUG_OBJECT (qtdemux,
11707 ">1 stream with unknown bitrate - bailing");
11710 stream = qtdemux->streams[i];
11714 /* For other subtypes, we assume no significant impact on bitrate */
11720 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
11724 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
11726 if (sys_bitrate < sum_bitrate) {
11727 /* This can happen, since sum_bitrate might be derived from maximum
11728 * bitrates and not average bitrates */
11729 GST_DEBUG_OBJECT (qtdemux,
11730 "System bitrate less than sum bitrate - bailing");
11734 bitrate = sys_bitrate - sum_bitrate;
11735 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
11736 ", Stream bitrate = %u", sys_bitrate, bitrate);
11738 if (!stream->stream_tags)
11739 stream->stream_tags = gst_tag_list_new_empty ();
11741 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
11743 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11744 GST_TAG_BITRATE, bitrate, NULL);
11747 static GstFlowReturn
11748 qtdemux_prepare_streams (GstQTDemux * qtdemux)
11751 GstFlowReturn ret = GST_FLOW_OK;
11753 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
11755 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
11756 QtDemuxStream *stream = qtdemux->streams[i];
11757 guint32 sample_num = 0;
11759 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
11760 i, stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
11762 if (qtdemux->fragmented) {
11763 /* need all moov samples first */
11764 GST_OBJECT_LOCK (qtdemux);
11765 while (stream->n_samples == 0)
11766 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
11768 GST_OBJECT_UNLOCK (qtdemux);
11770 /* discard any stray moof */
11771 qtdemux->moof_offset = 0;
11774 /* prepare braking */
11775 if (ret != GST_FLOW_ERROR)
11778 /* in pull mode, we should have parsed some sample info by now;
11779 * and quite some code will not handle no samples.
11780 * in push mode, we'll just have to deal with it */
11781 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
11782 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
11783 gst_qtdemux_remove_stream (qtdemux, i);
11788 /* parse the initial sample for use in setting the frame rate cap */
11789 while (sample_num == 0 && sample_num < stream->n_samples) {
11790 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
11794 if (stream->n_samples > 0 && stream->stbl_index >= 0) {
11795 stream->first_duration = stream->samples[0].duration;
11796 GST_LOG_OBJECT (qtdemux, "stream %d first duration %u",
11797 stream->track_id, stream->first_duration);
11804 static GstFlowReturn
11805 qtdemux_expose_streams (GstQTDemux * qtdemux)
11808 GSList *oldpads = NULL;
11811 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
11813 for (i = 0; i < qtdemux->n_streams; i++) {
11814 QtDemuxStream *stream = qtdemux->streams[i];
11815 GstPad *oldpad = stream->pad;
11818 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
11819 i, stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
11821 if ((stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl) &&
11822 stream->track_id == qtdemux->chapters_track_id) {
11823 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
11824 so that it doesn't look like a subtitle track */
11825 gst_qtdemux_remove_stream (qtdemux, i);
11830 /* now we have all info and can expose */
11831 list = stream->stream_tags;
11832 stream->stream_tags = NULL;
11834 oldpads = g_slist_prepend (oldpads, oldpad);
11835 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
11836 return GST_FLOW_ERROR;
11839 gst_qtdemux_guess_bitrate (qtdemux);
11841 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
11843 for (iter = oldpads; iter; iter = g_slist_next (iter)) {
11844 GstPad *oldpad = iter->data;
11847 event = gst_event_new_eos ();
11848 if (qtdemux->segment_seqnum)
11849 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
11851 gst_pad_push_event (oldpad, event);
11852 gst_pad_set_active (oldpad, FALSE);
11853 gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
11854 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, oldpad);
11855 gst_object_unref (oldpad);
11858 /* check if we should post a redirect in case there is a single trak
11859 * and it is a redirecting trak */
11860 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
11863 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
11864 "an external content");
11865 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
11866 gst_structure_new ("redirect",
11867 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
11869 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
11870 qtdemux->posted_redirect = TRUE;
11873 for (i = 0; i < qtdemux->n_streams; i++) {
11874 QtDemuxStream *stream = qtdemux->streams[i];
11876 qtdemux_do_allocation (qtdemux, stream);
11879 qtdemux->exposed = TRUE;
11880 return GST_FLOW_OK;
11883 /* check if major or compatible brand is 3GP */
11884 static inline gboolean
11885 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
11888 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
11890 } else if (qtdemux->comp_brands != NULL) {
11894 gboolean res = FALSE;
11896 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
11899 while (size >= 4) {
11900 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
11905 gst_buffer_unmap (qtdemux->comp_brands, &map);
11912 /* check if tag is a spec'ed 3GP tag keyword storing a string */
11913 static inline gboolean
11914 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
11916 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
11917 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
11918 || fourcc == FOURCC_albm;
11922 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
11923 const char *tag, const char *dummy, GNode * node)
11925 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11929 gdouble longitude, latitude, altitude;
11932 len = QT_UINT32 (node->data);
11939 /* TODO: language code skipped */
11941 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
11944 /* do not alarm in trivial case, but bail out otherwise */
11945 if (*(data + offset) != 0) {
11946 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
11950 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
11951 GST_TAG_GEO_LOCATION_NAME, name, NULL);
11952 offset += strlen (name);
11956 if (len < offset + 2 + 4 + 4 + 4)
11959 /* +1 +1 = skip null-terminator and location role byte */
11961 /* table in spec says unsigned, semantics say negative has meaning ... */
11962 longitude = QT_SFP32 (data + offset);
11965 latitude = QT_SFP32 (data + offset);
11968 altitude = QT_SFP32 (data + offset);
11970 /* one invalid means all are invalid */
11971 if (longitude >= -180.0 && longitude <= 180.0 &&
11972 latitude >= -90.0 && latitude <= 90.0) {
11973 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
11974 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
11975 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
11976 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
11979 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
11986 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
11993 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
11994 const char *tag, const char *dummy, GNode * node)
12000 len = QT_UINT32 (node->data);
12004 y = QT_UINT16 ((guint8 *) node->data + 12);
12006 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
12009 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
12011 date = g_date_new_dmy (1, 1, y);
12012 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
12013 g_date_free (date);
12017 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
12018 const char *tag, const char *dummy, GNode * node)
12021 char *tag_str = NULL;
12026 len = QT_UINT32 (node->data);
12031 entity = (guint8 *) node->data + offset;
12032 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
12033 GST_DEBUG_OBJECT (qtdemux,
12034 "classification info: %c%c%c%c invalid classification entity",
12035 entity[0], entity[1], entity[2], entity[3]);
12040 table = QT_UINT16 ((guint8 *) node->data + offset);
12042 /* Language code skipped */
12046 /* Tag format: "XXXX://Y[YYYY]/classification info string"
12047 * XXXX: classification entity, fixed length 4 chars.
12048 * Y[YYYY]: classification table, max 5 chars.
12050 tag_str = g_strdup_printf ("----://%u/%s",
12051 table, (char *) node->data + offset);
12053 /* memcpy To be sure we're preserving byte order */
12054 memcpy (tag_str, entity, 4);
12055 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
12057 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
12066 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
12072 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
12073 const char *tag, const char *dummy, GNode * node)
12075 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12081 gboolean ret = TRUE;
12082 const gchar *charset = NULL;
12084 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12086 len = QT_UINT32 (data->data);
12087 type = QT_UINT32 ((guint8 *) data->data + 8);
12088 if (type == 0x00000001 && len > 16) {
12089 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
12092 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
12093 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
12096 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
12100 len = QT_UINT32 (node->data);
12101 type = QT_UINT32 ((guint8 *) node->data + 4);
12102 if ((type >> 24) == 0xa9 && len > 8 + 4) {
12106 /* Type starts with the (C) symbol, so the next data is a list
12107 * of (string size(16), language code(16), string) */
12109 str_len = QT_UINT16 ((guint8 *) node->data + 8);
12110 lang_code = QT_UINT16 ((guint8 *) node->data + 10);
12112 /* the string + fourcc + size + 2 16bit fields,
12113 * means that there are more tags in this atom */
12114 if (len > str_len + 8 + 4) {
12115 /* TODO how to represent the same tag in different languages? */
12116 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
12117 "text alternatives, reading only first one");
12121 len = MIN (len, str_len + 8 + 4); /* remove trailing strings that we don't use */
12122 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
12124 if (lang_code < 0x800) { /* MAC encoded string */
12127 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
12128 QT_FOURCC ((guint8 *) node->data + 4))) {
12129 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
12131 /* we go for 3GP style encoding if major brands claims so,
12132 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
12133 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
12134 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
12135 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
12137 /* 16-bit Language code is ignored here as well */
12138 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
12145 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
12146 ret = FALSE; /* may have to fallback */
12149 GError *err = NULL;
12151 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
12152 charset, NULL, NULL, &err);
12154 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
12155 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
12157 g_error_free (err);
12160 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
12161 len - offset, env_vars);
12164 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
12165 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
12169 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
12176 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
12177 const char *tag, const char *dummy, GNode * node)
12179 qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
12183 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
12184 const char *tag, const char *dummy, GNode * node)
12186 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12188 char *s, *t, *k = NULL;
12193 /* first try normal string tag if major brand not 3GP */
12194 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
12195 if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
12196 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
12197 * let's try it 3gpp way after minor safety check */
12199 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
12205 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
12209 len = QT_UINT32 (data);
12213 count = QT_UINT8 (data + 14);
12215 for (; count; count--) {
12218 if (offset + 1 > len)
12220 slen = QT_UINT8 (data + offset);
12222 if (offset + slen > len)
12224 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
12227 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
12229 t = g_strjoin (",", k, s, NULL);
12237 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
12244 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
12245 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
12254 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
12260 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
12261 const char *tag1, const char *tag2, GNode * node)
12268 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12270 len = QT_UINT32 (data->data);
12271 type = QT_UINT32 ((guint8 *) data->data + 8);
12272 if (type == 0x00000000 && len >= 22) {
12273 n1 = QT_UINT16 ((guint8 *) data->data + 18);
12274 n2 = QT_UINT16 ((guint8 *) data->data + 20);
12276 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
12277 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
12280 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
12281 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
12288 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
12289 const char *tag1, const char *dummy, GNode * node)
12296 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12298 len = QT_UINT32 (data->data);
12299 type = QT_UINT32 ((guint8 *) data->data + 8);
12300 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
12301 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
12302 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
12303 n1 = QT_UINT16 ((guint8 *) data->data + 16);
12305 /* do not add bpm=0 */
12306 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
12307 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
12315 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
12316 const char *tag1, const char *dummy, GNode * node)
12323 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12325 len = QT_UINT32 (data->data);
12326 type = QT_UINT32 ((guint8 *) data->data + 8);
12327 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
12328 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
12329 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
12330 num = QT_UINT32 ((guint8 *) data->data + 16);
12332 /* do not add num=0 */
12333 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
12334 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
12341 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
12342 const char *tag1, const char *dummy, GNode * node)
12349 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12351 len = QT_UINT32 (data->data);
12352 type = QT_UINT32 ((guint8 *) data->data + 8);
12353 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
12354 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
12355 GstTagImageType image_type;
12357 if (gst_tag_list_get_tag_size (taglist, GST_TAG_IMAGE) == 0)
12358 image_type = GST_TAG_IMAGE_TYPE_FRONT_COVER;
12360 image_type = GST_TAG_IMAGE_TYPE_NONE;
12363 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
12364 len - 16, image_type))) {
12365 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
12366 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
12367 gst_sample_unref (sample);
12374 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
12375 const char *tag, const char *dummy, GNode * node)
12382 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12384 len = QT_UINT32 (data->data);
12385 type = QT_UINT32 ((guint8 *) data->data + 8);
12386 if (type == 0x00000001 && len > 16) {
12387 guint y, m = 1, d = 1;
12390 s = g_strndup ((char *) data->data + 16, len - 16);
12391 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
12392 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
12393 if (ret >= 1 && y > 1500 && y < 3000) {
12396 date = g_date_new_dmy (d, m, y);
12397 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
12398 g_date_free (date);
12400 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
12408 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
12409 const char *tag, const char *dummy, GNode * node)
12413 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12415 /* re-route to normal string tag if major brand says so
12416 * or no data atom and compatible brand suggests so */
12417 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
12418 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
12419 qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
12424 guint len, type, n;
12426 len = QT_UINT32 (data->data);
12427 type = QT_UINT32 ((guint8 *) data->data + 8);
12428 if (type == 0x00000000 && len >= 18) {
12429 n = QT_UINT16 ((guint8 *) data->data + 16);
12431 const gchar *genre;
12433 genre = gst_tag_id3_genre_get (n - 1);
12434 if (genre != NULL) {
12435 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
12436 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
12444 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
12445 const gchar * tag, guint8 * data, guint32 datasize)
12450 /* make a copy to have \0 at the end */
12451 datacopy = g_strndup ((gchar *) data, datasize);
12453 /* convert the str to double */
12454 if (sscanf (datacopy, "%lf", &value) == 1) {
12455 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
12456 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
12458 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
12466 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
12467 const char *tag, const char *tag_bis, GNode * node)
12476 const gchar *meanstr;
12477 const gchar *namestr;
12479 /* checking the whole ---- atom size for consistency */
12480 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
12481 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
12485 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
12487 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
12491 meansize = QT_UINT32 (mean->data);
12492 if (meansize <= 12) {
12493 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
12496 meanstr = ((gchar *) mean->data) + 12;
12499 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
12501 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
12505 namesize = QT_UINT32 (name->data);
12506 if (namesize <= 12) {
12507 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
12510 namestr = ((gchar *) name->data) + 12;
12518 * uint24 - data type
12522 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12524 GST_WARNING_OBJECT (demux, "No data atom in this tag");
12527 datasize = QT_UINT32 (data->data);
12528 if (datasize <= 16) {
12529 GST_WARNING_OBJECT (demux, "Data atom too small");
12532 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
12534 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
12535 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
12536 static const struct
12538 const gchar name[28];
12539 const gchar tag[28];
12542 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
12543 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
12544 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
12545 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
12546 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
12547 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
12548 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
12549 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
12553 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
12554 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
12555 switch (gst_tag_get_type (tags[i].tag)) {
12556 case G_TYPE_DOUBLE:
12557 qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
12558 ((guint8 *) data->data) + 16, datasize - 16);
12560 case G_TYPE_STRING:
12561 qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
12570 if (i == G_N_ELEMENTS (tags))
12580 #ifndef GST_DISABLE_GST_DEBUG
12582 gchar *namestr_dbg;
12583 gchar *meanstr_dbg;
12585 meanstr_dbg = g_strndup (meanstr, meansize);
12586 namestr_dbg = g_strndup (namestr, namesize);
12588 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
12589 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
12591 g_free (namestr_dbg);
12592 g_free (meanstr_dbg);
12599 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
12600 const char *tag_bis, GNode * node)
12605 GstTagList *id32_taglist = NULL;
12607 GST_LOG_OBJECT (demux, "parsing ID32");
12610 len = GST_READ_UINT32_BE (data);
12612 /* need at least full box and language tag */
12616 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
12617 gst_buffer_fill (buf, 0, data + 14, len - 14);
12619 id32_taglist = gst_tag_list_from_id3v2_tag (buf);
12620 if (id32_taglist) {
12621 GST_LOG_OBJECT (demux, "parsing ok");
12622 gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
12623 gst_tag_list_unref (id32_taglist);
12625 GST_LOG_OBJECT (demux, "parsing failed");
12628 gst_buffer_unref (buf);
12631 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
12632 const char *tag, const char *tag_bis, GNode * node);
12635 FOURCC_pcst -> if media is a podcast -> bool
12636 FOURCC_cpil -> if media is part of a compilation -> bool
12637 FOURCC_pgap -> if media is part of a gapless context -> bool
12638 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
12641 static const struct
12644 const gchar *gst_tag;
12645 const gchar *gst_tag_bis;
12646 const GstQTDemuxAddTagFunc func;
12649 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
12650 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
12651 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
12652 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
12653 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
12654 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
12655 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
12656 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
12657 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
12658 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
12659 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
12660 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
12661 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
12662 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12663 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12664 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12665 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
12666 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
12667 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
12668 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
12669 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
12670 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
12671 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
12672 qtdemux_tag_add_num}, {
12673 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
12674 qtdemux_tag_add_num}, {
12675 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
12676 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
12677 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
12678 FOURCC_covr, GST_TAG_IMAGE, NULL, qtdemux_tag_add_covr}, {
12679 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
12680 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
12681 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
12682 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
12683 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
12684 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
12685 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
12686 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
12687 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
12688 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
12689 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
12690 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
12691 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
12692 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
12693 qtdemux_tag_add_classification}, {
12694 FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
12695 FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
12696 FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
12698 /* This is a special case, some tags are stored in this
12699 * 'reverse dns naming', according to:
12700 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
12703 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
12704 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
12705 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
12708 struct _GstQtDemuxTagList
12711 GstTagList *taglist;
12713 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
12716 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
12722 const gchar *style;
12727 GstQTDemux *demux = qtdemuxtaglist->demux;
12728 GstTagList *taglist = qtdemuxtaglist->taglist;
12731 len = QT_UINT32 (data);
12732 buf = gst_buffer_new_and_alloc (len);
12733 gst_buffer_fill (buf, 0, data, len);
12735 /* heuristic to determine style of tag */
12736 if (QT_FOURCC (data + 4) == FOURCC_____ ||
12737 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
12739 else if (demux->major_brand == FOURCC_qt__)
12740 style = "quicktime";
12741 /* fall back to assuming iso/3gp tag style */
12745 /* santize the name for the caps. */
12746 for (i = 0; i < 4; i++) {
12747 guint8 d = data[4 + i];
12748 if (g_ascii_isalnum (d))
12749 ndata[i] = g_ascii_tolower (d);
12754 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
12755 ndata[0], ndata[1], ndata[2], ndata[3]);
12756 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
12758 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
12759 sample = gst_sample_new (buf, NULL, NULL, s);
12760 gst_buffer_unref (buf);
12761 g_free (media_type);
12763 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
12766 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
12767 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
12769 gst_sample_unref (sample);
12773 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
12780 GstQtDemuxTagList demuxtaglist;
12782 demuxtaglist.demux = qtdemux;
12783 demuxtaglist.taglist = taglist;
12785 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
12786 if (meta != NULL) {
12787 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
12788 if (ilst == NULL) {
12789 GST_LOG_OBJECT (qtdemux, "no ilst");
12794 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
12798 while (i < G_N_ELEMENTS (add_funcs)) {
12799 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
12803 len = QT_UINT32 (node->data);
12805 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
12806 GST_FOURCC_ARGS (add_funcs[i].fourcc));
12808 add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
12809 add_funcs[i].gst_tag_bis, node);
12811 g_node_destroy (node);
12817 /* parsed nodes have been removed, pass along remainder as blob */
12818 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
12819 (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
12821 /* parse up XMP_ node if existing */
12822 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
12823 if (xmp_ != NULL) {
12825 GstTagList *xmptaglist;
12827 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
12828 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
12829 xmptaglist = gst_tag_list_from_xmp_buffer (buf);
12830 gst_buffer_unref (buf);
12832 qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
12834 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
12840 GstStructure *structure; /* helper for sort function */
12842 guint min_req_bitrate;
12843 guint min_req_qt_version;
12847 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
12849 GstQtReference *ref_a = (GstQtReference *) a;
12850 GstQtReference *ref_b = (GstQtReference *) b;
12852 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
12853 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
12855 /* known bitrates go before unknown; higher bitrates go first */
12856 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
12859 /* sort the redirects and post a message for the application.
12862 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
12864 GstQtReference *best;
12867 GValue list_val = { 0, };
12870 g_assert (references != NULL);
12872 references = g_list_sort (references, qtdemux_redirects_sort_func);
12874 best = (GstQtReference *) references->data;
12876 g_value_init (&list_val, GST_TYPE_LIST);
12878 for (l = references; l != NULL; l = l->next) {
12879 GstQtReference *ref = (GstQtReference *) l->data;
12880 GValue struct_val = { 0, };
12882 ref->structure = gst_structure_new ("redirect",
12883 "new-location", G_TYPE_STRING, ref->location, NULL);
12885 if (ref->min_req_bitrate > 0) {
12886 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
12887 ref->min_req_bitrate, NULL);
12890 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
12891 g_value_set_boxed (&struct_val, ref->structure);
12892 gst_value_list_append_value (&list_val, &struct_val);
12893 g_value_unset (&struct_val);
12894 /* don't free anything here yet, since we need best->structure below */
12897 g_assert (best != NULL);
12898 s = gst_structure_copy (best->structure);
12900 if (g_list_length (references) > 1) {
12901 gst_structure_set_value (s, "locations", &list_val);
12904 g_value_unset (&list_val);
12906 for (l = references; l != NULL; l = l->next) {
12907 GstQtReference *ref = (GstQtReference *) l->data;
12909 gst_structure_free (ref->structure);
12910 g_free (ref->location);
12913 g_list_free (references);
12915 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
12916 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
12917 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
12918 qtdemux->posted_redirect = TRUE;
12921 /* look for redirect nodes, collect all redirect information and
12925 qtdemux_parse_redirects (GstQTDemux * qtdemux)
12927 GNode *rmra, *rmda, *rdrf;
12929 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
12931 GList *redirects = NULL;
12933 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
12935 GstQtReference ref = { NULL, NULL, 0, 0 };
12936 GNode *rmdr, *rmvc;
12938 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
12939 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
12940 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
12941 ref.min_req_bitrate);
12944 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
12945 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
12946 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
12948 #ifndef GST_DISABLE_GST_DEBUG
12949 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
12951 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
12953 GST_LOG_OBJECT (qtdemux,
12954 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
12955 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
12956 bitmask, check_type);
12957 if (package == FOURCC_qtim && check_type == 0) {
12958 ref.min_req_qt_version = version;
12962 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
12968 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
12969 if (ref_len > 20) {
12970 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
12971 ref_data = (guint8 *) rdrf->data + 20;
12972 if (ref_type == FOURCC_alis) {
12973 guint record_len, record_version, fn_len;
12975 if (ref_len > 70) {
12976 /* MacOSX alias record, google for alias-layout.txt */
12977 record_len = QT_UINT16 (ref_data + 4);
12978 record_version = QT_UINT16 (ref_data + 4 + 2);
12979 fn_len = QT_UINT8 (ref_data + 50);
12980 if (record_len > 50 && record_version == 2 && fn_len > 0) {
12981 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
12984 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
12987 } else if (ref_type == FOURCC_url_) {
12988 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
12990 GST_DEBUG_OBJECT (qtdemux,
12991 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
12992 GST_FOURCC_ARGS (ref_type));
12994 if (ref.location != NULL) {
12995 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
12997 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
12999 GST_WARNING_OBJECT (qtdemux,
13000 "Failed to extract redirect location from rdrf atom");
13003 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
13007 /* look for others */
13008 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
13011 if (redirects != NULL) {
13012 qtdemux_process_redirects (qtdemux, redirects);
13018 static GstTagList *
13019 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
13023 if (tags == NULL) {
13024 tags = gst_tag_list_new_empty ();
13025 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
13028 if (qtdemux->major_brand == FOURCC_mjp2)
13029 fmt = "Motion JPEG 2000";
13030 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
13032 else if (qtdemux->major_brand == FOURCC_qt__)
13034 else if (qtdemux->fragmented)
13037 fmt = "ISO MP4/M4A";
13039 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
13040 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
13042 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
13048 /* we have read the complete moov node now.
13049 * This function parses all of the relevant info, creates the traks and
13050 * prepares all data structures for playback
13053 qtdemux_parse_tree (GstQTDemux * qtdemux)
13059 GstClockTime duration;
13061 guint64 creation_time;
13062 GstDateTime *datetime = NULL;
13065 /* make sure we have a usable taglist */
13066 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13068 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
13069 if (mvhd == NULL) {
13070 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
13071 return qtdemux_parse_redirects (qtdemux);
13074 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
13075 if (version == 1) {
13076 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
13077 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
13078 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
13079 } else if (version == 0) {
13080 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
13081 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
13082 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
13084 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
13088 /* Moving qt creation time (secs since 1904) to unix time */
13089 if (creation_time != 0) {
13090 /* Try to use epoch first as it should be faster and more commonly found */
13091 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
13094 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
13095 /* some data cleansing sanity */
13096 g_get_current_time (&now);
13097 if (now.tv_sec + 24 * 3600 < creation_time) {
13098 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
13100 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
13103 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
13104 GDateTime *dt, *dt_local;
13106 dt = g_date_time_add_seconds (base_dt, creation_time);
13107 dt_local = g_date_time_to_local (dt);
13108 datetime = gst_date_time_new_from_g_date_time (dt_local);
13110 g_date_time_unref (base_dt);
13111 g_date_time_unref (dt);
13115 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
13116 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
13118 gst_date_time_unref (datetime);
13121 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
13122 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
13124 /* check for fragmented file and get some (default) data */
13125 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
13128 GstByteReader mehd_data;
13130 /* let track parsing or anyone know weird stuff might happen ... */
13131 qtdemux->fragmented = TRUE;
13133 /* compensate for total duration */
13134 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
13136 qtdemux_parse_mehd (qtdemux, &mehd_data);
13139 /* set duration in the segment info */
13140 gst_qtdemux_get_duration (qtdemux, &duration);
13142 qtdemux->segment.duration = duration;
13143 /* also do not exceed duration; stop is set that way post seek anyway,
13144 * and segment activation falls back to duration,
13145 * whereas loop only checks stop, so let's align this here as well */
13146 qtdemux->segment.stop = duration;
13149 /* parse all traks */
13150 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
13152 qtdemux_parse_trak (qtdemux, trak);
13153 /* iterate all siblings */
13154 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
13157 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13160 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
13162 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13164 GST_LOG_OBJECT (qtdemux, "No udta node found.");
13167 /* maybe also some tags in meta box */
13168 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
13170 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
13171 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13173 GST_LOG_OBJECT (qtdemux, "No meta node found.");
13176 /* parse any protection system info */
13177 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
13179 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
13180 qtdemux_parse_pssh (qtdemux, pssh);
13181 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
13184 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
13189 /* taken from ffmpeg */
13191 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
13203 len = (len << 7) | (c & 0x7f);
13211 /* this can change the codec originally present in @list */
13213 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
13214 QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
13216 int len = QT_UINT32 (esds->data);
13217 guint8 *ptr = esds->data;
13218 guint8 *end = ptr + len;
13220 guint8 *data_ptr = NULL;
13222 guint8 object_type_id = 0;
13223 const char *codec_name = NULL;
13224 GstCaps *caps = NULL;
13226 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
13228 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
13230 while (ptr + 1 < end) {
13231 tag = QT_UINT8 (ptr);
13232 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
13234 len = read_descr_size (ptr, end, &ptr);
13235 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
13237 /* Check the stated amount of data is available for reading */
13238 if (len < 0 || ptr + len > end)
13242 case ES_DESCRIPTOR_TAG:
13243 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
13244 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
13247 case DECODER_CONFIG_DESC_TAG:{
13248 guint max_bitrate, avg_bitrate;
13250 object_type_id = QT_UINT8 (ptr);
13251 max_bitrate = QT_UINT32 (ptr + 5);
13252 avg_bitrate = QT_UINT32 (ptr + 9);
13253 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
13254 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
13255 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
13256 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
13257 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
13258 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
13259 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
13260 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
13262 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
13263 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
13264 avg_bitrate, NULL);
13269 case DECODER_SPECIFIC_INFO_TAG:
13270 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
13271 if (object_type_id == 0xe0 && len == 0x40) {
13277 GST_DEBUG_OBJECT (qtdemux,
13278 "Have VOBSUB palette. Creating palette event");
13279 /* move to decConfigDescr data and read palette */
13281 for (i = 0; i < 16; i++) {
13282 clut[i] = QT_UINT32 (data);
13286 s = gst_structure_new ("application/x-gst-dvd", "event",
13287 G_TYPE_STRING, "dvd-spu-clut-change",
13288 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
13289 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
13290 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
13291 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
13292 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
13293 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
13294 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
13295 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
13298 /* store event and trigger custom processing */
13299 stream->pending_event =
13300 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
13302 /* Generic codec_data handler puts it on the caps */
13309 case SL_CONFIG_DESC_TAG:
13310 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
13314 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
13316 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
13322 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
13323 * in use, and should also be used to override some other parameters for some
13325 switch (object_type_id) {
13326 case 0x20: /* MPEG-4 */
13327 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
13328 * profile_and_level_indication */
13329 if (data_ptr != NULL && data_len >= 5 &&
13330 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
13331 gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
13332 data_ptr + 4, data_len - 4);
13334 break; /* Nothing special needed here */
13335 case 0x21: /* H.264 */
13336 codec_name = "H.264 / AVC";
13337 caps = gst_caps_new_simple ("video/x-h264",
13338 "stream-format", G_TYPE_STRING, "avc",
13339 "alignment", G_TYPE_STRING, "au", NULL);
13341 case 0x40: /* AAC (any) */
13342 case 0x66: /* AAC Main */
13343 case 0x67: /* AAC LC */
13344 case 0x68: /* AAC SSR */
13345 /* Override channels and rate based on the codec_data, as it's often
13347 /* Only do so for basic setup without HE-AAC extension */
13348 if (data_ptr && data_len == 2) {
13349 guint channels, rate;
13351 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
13353 entry->n_channels = channels;
13355 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
13357 entry->rate = rate;
13360 /* Set level and profile if possible */
13361 if (data_ptr != NULL && data_len >= 2) {
13362 gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
13363 data_ptr, data_len);
13365 const gchar *profile_str = NULL;
13368 guint8 *codec_data;
13369 gint rate_idx, profile;
13371 /* No codec_data, let's invent something.
13372 * FIXME: This is wrong for SBR! */
13374 GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
13376 buffer = gst_buffer_new_and_alloc (2);
13377 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
13378 codec_data = map.data;
13381 gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
13384 switch (object_type_id) {
13386 profile_str = "main";
13390 profile_str = "lc";
13394 profile_str = "ssr";
13402 codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
13404 ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
13406 gst_buffer_unmap (buffer, &map);
13407 gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
13408 GST_TYPE_BUFFER, buffer, NULL);
13409 gst_buffer_unref (buffer);
13412 gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
13413 G_TYPE_STRING, profile_str, NULL);
13417 case 0x60: /* MPEG-2, various profiles */
13423 codec_name = "MPEG-2 video";
13424 caps = gst_caps_new_simple ("video/mpeg",
13425 "mpegversion", G_TYPE_INT, 2,
13426 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13428 case 0x69: /* MPEG-2 BC audio */
13429 case 0x6B: /* MPEG-1 audio */
13430 caps = gst_caps_new_simple ("audio/mpeg",
13431 "mpegversion", G_TYPE_INT, 1, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
13432 codec_name = "MPEG-1 audio";
13434 case 0x6A: /* MPEG-1 */
13435 codec_name = "MPEG-1 video";
13436 caps = gst_caps_new_simple ("video/mpeg",
13437 "mpegversion", G_TYPE_INT, 1,
13438 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13440 case 0x6C: /* MJPEG */
13442 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13444 codec_name = "Motion-JPEG";
13446 case 0x6D: /* PNG */
13448 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
13450 codec_name = "PNG still images";
13452 case 0x6E: /* JPEG2000 */
13453 codec_name = "JPEG-2000";
13454 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
13456 case 0xA4: /* Dirac */
13457 codec_name = "Dirac";
13458 caps = gst_caps_new_empty_simple ("video/x-dirac");
13460 case 0xA5: /* AC3 */
13461 codec_name = "AC-3 audio";
13462 caps = gst_caps_new_simple ("audio/x-ac3",
13463 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13465 case 0xA9: /* AC3 */
13466 codec_name = "DTS audio";
13467 caps = gst_caps_new_simple ("audio/x-dts",
13468 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13470 case 0xE1: /* QCELP */
13471 /* QCELP, the codec_data is a riff tag (little endian) with
13472 * 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). */
13473 caps = gst_caps_new_empty_simple ("audio/qcelp");
13474 codec_name = "QCELP";
13480 /* If we have a replacement caps, then change our caps for this stream */
13482 gst_caps_unref (entry->caps);
13483 entry->caps = caps;
13486 if (codec_name && list)
13487 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
13488 GST_TAG_AUDIO_CODEC, codec_name, NULL);
13490 /* Add the codec_data attribute to caps, if we have it */
13494 buffer = gst_buffer_new_and_alloc (data_len);
13495 gst_buffer_fill (buffer, 0, data_ptr, data_len);
13497 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
13498 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
13500 gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
13502 gst_buffer_unref (buffer);
13507 static inline GstCaps *
13508 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
13512 char *s, fourstr[5];
13514 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13515 for (i = 0; i < 4; i++) {
13516 if (!g_ascii_isalnum (fourstr[i]))
13519 s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
13520 caps = gst_caps_new_empty_simple (s);
13525 #define _codec(name) \
13527 if (codec_name) { \
13528 *codec_name = g_strdup (name); \
13533 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13534 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
13535 const guint8 * stsd_entry_data, gchar ** codec_name)
13537 GstCaps *caps = NULL;
13538 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
13541 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
13542 _codec ("PNG still images");
13543 caps = gst_caps_new_empty_simple ("image/png");
13546 _codec ("JPEG still images");
13548 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13551 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
13552 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
13553 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
13554 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
13555 _codec ("Motion-JPEG");
13557 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13560 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
13561 _codec ("Motion-JPEG format B");
13562 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
13565 _codec ("JPEG-2000");
13566 /* override to what it should be according to spec, avoid palette_data */
13567 entry->bits_per_sample = 24;
13568 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
13571 _codec ("Sorensen video v.3");
13572 caps = gst_caps_new_simple ("video/x-svq",
13573 "svqversion", G_TYPE_INT, 3, NULL);
13575 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
13576 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
13577 _codec ("Sorensen video v.1");
13578 caps = gst_caps_new_simple ("video/x-svq",
13579 "svqversion", G_TYPE_INT, 1, NULL);
13581 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
13582 caps = gst_caps_new_empty_simple ("video/x-raw");
13583 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
13584 _codec ("Windows Raw RGB");
13585 stream->alignment = 32;
13591 bps = QT_UINT16 (stsd_entry_data + 82);
13594 format = GST_VIDEO_FORMAT_RGB15;
13597 format = GST_VIDEO_FORMAT_RGB16;
13600 format = GST_VIDEO_FORMAT_RGB;
13603 format = GST_VIDEO_FORMAT_ARGB;
13611 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
13612 format = GST_VIDEO_FORMAT_I420;
13614 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
13615 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
13616 format = GST_VIDEO_FORMAT_I420;
13619 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
13620 format = GST_VIDEO_FORMAT_UYVY;
13622 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
13623 format = GST_VIDEO_FORMAT_v308;
13625 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
13626 format = GST_VIDEO_FORMAT_v216;
13629 format = GST_VIDEO_FORMAT_v210;
13631 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
13632 format = GST_VIDEO_FORMAT_r210;
13634 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
13635 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
13636 format = GST_VIDEO_FORMAT_v410;
13639 /* Packed YUV 4:4:4:4 8 bit in 32 bits
13640 * but different order than AYUV
13641 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
13642 format = GST_VIDEO_FORMAT_v408;
13645 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
13646 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
13647 _codec ("MPEG-1 video");
13648 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
13649 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13651 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
13652 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
13653 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
13654 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
13655 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
13656 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
13657 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
13658 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
13659 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
13660 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
13661 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
13662 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
13663 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
13664 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
13665 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
13666 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
13667 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
13668 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
13669 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
13670 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
13671 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
13672 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
13673 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
13674 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
13675 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
13676 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
13677 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
13678 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
13679 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
13680 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
13681 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
13682 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
13683 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
13684 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
13685 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
13686 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
13687 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
13688 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
13689 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
13690 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
13691 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
13692 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
13693 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
13694 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
13695 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
13696 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
13697 case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
13698 _codec ("MPEG-2 video");
13699 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
13700 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13702 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
13703 _codec ("GIF still images");
13704 caps = gst_caps_new_empty_simple ("image/gif");
13707 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
13709 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
13711 /* ffmpeg uses the height/width props, don't know why */
13712 caps = gst_caps_new_simple ("video/x-h263",
13713 "variant", G_TYPE_STRING, "itu", NULL);
13717 _codec ("MPEG-4 video");
13718 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
13719 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13721 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
13722 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
13723 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
13724 caps = gst_caps_new_simple ("video/x-msmpeg",
13725 "msmpegversion", G_TYPE_INT, 43, NULL);
13727 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
13729 caps = gst_caps_new_simple ("video/x-divx",
13730 "divxversion", G_TYPE_INT, 3, NULL);
13732 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
13733 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
13735 caps = gst_caps_new_simple ("video/x-divx",
13736 "divxversion", G_TYPE_INT, 4, NULL);
13738 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
13740 caps = gst_caps_new_simple ("video/x-divx",
13741 "divxversion", G_TYPE_INT, 5, NULL);
13744 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
13746 caps = gst_caps_new_simple ("video/x-ffv",
13747 "ffvversion", G_TYPE_INT, 1, NULL);
13750 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
13751 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
13756 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
13757 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
13758 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13762 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
13763 _codec ("Cinepak");
13764 caps = gst_caps_new_empty_simple ("video/x-cinepak");
13766 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
13767 _codec ("Apple QuickDraw");
13768 caps = gst_caps_new_empty_simple ("video/x-qdrw");
13770 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
13771 _codec ("Apple video");
13772 caps = gst_caps_new_empty_simple ("video/x-apple-video");
13776 _codec ("H.264 / AVC");
13777 caps = gst_caps_new_simple ("video/x-h264",
13778 "stream-format", G_TYPE_STRING, "avc",
13779 "alignment", G_TYPE_STRING, "au", NULL);
13782 _codec ("H.264 / AVC");
13783 caps = gst_caps_new_simple ("video/x-h264",
13784 "stream-format", G_TYPE_STRING, "avc3",
13785 "alignment", G_TYPE_STRING, "au", NULL);
13789 _codec ("H.265 / HEVC");
13790 caps = gst_caps_new_simple ("video/x-h265",
13791 "stream-format", G_TYPE_STRING, "hvc1",
13792 "alignment", G_TYPE_STRING, "au", NULL);
13795 _codec ("H.265 / HEVC");
13796 caps = gst_caps_new_simple ("video/x-h265",
13797 "stream-format", G_TYPE_STRING, "hev1",
13798 "alignment", G_TYPE_STRING, "au", NULL);
13801 _codec ("Run-length encoding");
13802 caps = gst_caps_new_simple ("video/x-rle",
13803 "layout", G_TYPE_STRING, "quicktime", NULL);
13806 _codec ("Run-length encoding");
13807 caps = gst_caps_new_simple ("video/x-rle",
13808 "layout", G_TYPE_STRING, "microsoft", NULL);
13810 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
13811 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
13812 _codec ("Indeo Video 3");
13813 caps = gst_caps_new_simple ("video/x-indeo",
13814 "indeoversion", G_TYPE_INT, 3, NULL);
13816 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
13817 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
13818 _codec ("Intel Video 4");
13819 caps = gst_caps_new_simple ("video/x-indeo",
13820 "indeoversion", G_TYPE_INT, 4, NULL);
13824 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
13825 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
13826 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
13827 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
13828 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
13829 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
13830 _codec ("DV Video");
13831 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
13832 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13834 case FOURCC_dv5n: /* DVCPRO50 NTSC */
13835 case FOURCC_dv5p: /* DVCPRO50 PAL */
13836 _codec ("DVCPro50 Video");
13837 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
13838 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13840 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
13841 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
13842 _codec ("DVCProHD Video");
13843 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
13844 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13846 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
13847 _codec ("Apple Graphics (SMC)");
13848 caps = gst_caps_new_empty_simple ("video/x-smc");
13850 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
13852 caps = gst_caps_new_empty_simple ("video/x-vp3");
13854 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
13855 _codec ("VP6 Flash");
13856 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
13860 caps = gst_caps_new_empty_simple ("video/x-theora");
13861 /* theora uses one byte of padding in the data stream because it does not
13862 * allow 0 sized packets while theora does */
13863 entry->padding = 1;
13867 caps = gst_caps_new_empty_simple ("video/x-dirac");
13869 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
13870 _codec ("TIFF still images");
13871 caps = gst_caps_new_empty_simple ("image/tiff");
13873 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
13874 _codec ("Apple Intermediate Codec");
13875 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
13877 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
13878 _codec ("AVID DNxHD");
13879 caps = gst_caps_from_string ("video/x-dnxhd");
13882 _codec ("On2 VP8");
13883 caps = gst_caps_from_string ("video/x-vp8");
13886 _codec ("Apple ProRes LT");
13888 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
13892 _codec ("Apple ProRes HQ");
13894 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
13898 _codec ("Apple ProRes");
13900 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13904 _codec ("Apple ProRes Proxy");
13906 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13910 _codec ("Apple ProRes 4444");
13912 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13916 _codec ("Apple ProRes 4444 XQ");
13918 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13922 _codec ("GoPro CineForm");
13923 caps = gst_caps_from_string ("video/x-cineform");
13928 caps = gst_caps_new_simple ("video/x-wmv",
13929 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
13931 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
13934 caps = _get_unknown_codec_name ("video", fourcc);
13939 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
13942 gst_video_info_init (&info);
13943 gst_video_info_set_format (&info, format, entry->width, entry->height);
13945 caps = gst_video_info_to_caps (&info);
13946 *codec_name = gst_pb_utils_get_codec_description (caps);
13948 /* enable clipping for raw video streams */
13949 stream->need_clip = TRUE;
13950 stream->alignment = 32;
13957 round_up_pow2 (guint n)
13969 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13970 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
13971 int len, gchar ** codec_name)
13974 const GstStructure *s;
13977 GstAudioFormat format = 0;
13980 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
13982 depth = entry->bytes_per_packet * 8;
13985 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
13987 /* 8-bit audio is unsigned */
13989 format = GST_AUDIO_FORMAT_U8;
13990 /* otherwise it's signed and big-endian just like 'twos' */
13992 endian = G_BIG_ENDIAN;
13999 endian = G_LITTLE_ENDIAN;
14002 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
14004 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
14008 caps = gst_caps_new_simple ("audio/x-raw",
14009 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14010 "layout", G_TYPE_STRING, "interleaved", NULL);
14011 stream->alignment = GST_ROUND_UP_8 (depth);
14012 stream->alignment = round_up_pow2 (stream->alignment);
14015 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
14016 _codec ("Raw 64-bit floating-point audio");
14017 caps = gst_caps_new_simple ("audio/x-raw",
14018 "format", G_TYPE_STRING, "F64BE",
14019 "layout", G_TYPE_STRING, "interleaved", NULL);
14020 stream->alignment = 8;
14022 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
14023 _codec ("Raw 32-bit floating-point audio");
14024 caps = gst_caps_new_simple ("audio/x-raw",
14025 "format", G_TYPE_STRING, "F32BE",
14026 "layout", G_TYPE_STRING, "interleaved", NULL);
14027 stream->alignment = 4;
14030 _codec ("Raw 24-bit PCM audio");
14031 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14033 caps = gst_caps_new_simple ("audio/x-raw",
14034 "format", G_TYPE_STRING, "S24BE",
14035 "layout", G_TYPE_STRING, "interleaved", NULL);
14036 stream->alignment = 4;
14038 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
14039 _codec ("Raw 32-bit PCM audio");
14040 caps = gst_caps_new_simple ("audio/x-raw",
14041 "format", G_TYPE_STRING, "S32BE",
14042 "layout", G_TYPE_STRING, "interleaved", NULL);
14043 stream->alignment = 4;
14045 case GST_MAKE_FOURCC ('s', '1', '6', 'l'):
14046 _codec ("Raw 16-bit PCM audio");
14047 caps = gst_caps_new_simple ("audio/x-raw",
14048 "format", G_TYPE_STRING, "S16LE",
14049 "layout", G_TYPE_STRING, "interleaved", NULL);
14050 stream->alignment = 2;
14053 _codec ("Mu-law audio");
14054 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
14057 _codec ("A-law audio");
14058 caps = gst_caps_new_empty_simple ("audio/x-alaw");
14062 _codec ("Microsoft ADPCM");
14063 /* Microsoft ADPCM-ACM code 2 */
14064 caps = gst_caps_new_simple ("audio/x-adpcm",
14065 "layout", G_TYPE_STRING, "microsoft", NULL);
14069 _codec ("DVI/IMA ADPCM");
14070 caps = gst_caps_new_simple ("audio/x-adpcm",
14071 "layout", G_TYPE_STRING, "dvi", NULL);
14075 _codec ("DVI/Intel IMA ADPCM");
14076 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
14077 caps = gst_caps_new_simple ("audio/x-adpcm",
14078 "layout", G_TYPE_STRING, "quicktime", NULL);
14082 /* MPEG layer 3, CBR only (pre QT4.1) */
14084 _codec ("MPEG-1 layer 3");
14085 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
14086 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
14087 "mpegversion", G_TYPE_INT, 1, NULL);
14089 case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
14090 _codec ("MPEG-1 layer 2");
14092 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
14093 "mpegversion", G_TYPE_INT, 1, NULL);
14096 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
14097 _codec ("EAC-3 audio");
14098 caps = gst_caps_new_simple ("audio/x-eac3",
14099 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14100 entry->sampled = TRUE;
14102 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
14104 _codec ("AC-3 audio");
14105 caps = gst_caps_new_simple ("audio/x-ac3",
14106 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14107 entry->sampled = TRUE;
14109 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
14110 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
14111 _codec ("DTS audio");
14112 caps = gst_caps_new_simple ("audio/x-dts",
14113 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14114 entry->sampled = TRUE;
14116 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
14117 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
14118 _codec ("DTS-HD audio");
14119 caps = gst_caps_new_simple ("audio/x-dts",
14120 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14121 entry->sampled = TRUE;
14125 caps = gst_caps_new_simple ("audio/x-mace",
14126 "maceversion", G_TYPE_INT, 3, NULL);
14130 caps = gst_caps_new_simple ("audio/x-mace",
14131 "maceversion", G_TYPE_INT, 6, NULL);
14133 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
14135 caps = gst_caps_new_empty_simple ("application/ogg");
14137 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
14138 _codec ("DV audio");
14139 caps = gst_caps_new_empty_simple ("audio/x-dv");
14142 _codec ("MPEG-4 AAC audio");
14143 caps = gst_caps_new_simple ("audio/mpeg",
14144 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
14145 "stream-format", G_TYPE_STRING, "raw", NULL);
14147 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
14148 _codec ("QDesign Music");
14149 caps = gst_caps_new_empty_simple ("audio/x-qdm");
14152 _codec ("QDesign Music v.2");
14153 /* FIXME: QDesign music version 2 (no constant) */
14154 if (FALSE && data) {
14155 caps = gst_caps_new_simple ("audio/x-qdm2",
14156 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
14157 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
14158 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
14160 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
14164 _codec ("GSM audio");
14165 caps = gst_caps_new_empty_simple ("audio/x-gsm");
14168 _codec ("AMR audio");
14169 caps = gst_caps_new_empty_simple ("audio/AMR");
14172 _codec ("AMR-WB audio");
14173 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
14176 _codec ("Quicktime IMA ADPCM");
14177 caps = gst_caps_new_simple ("audio/x-adpcm",
14178 "layout", G_TYPE_STRING, "quicktime", NULL);
14181 _codec ("Apple lossless audio");
14182 caps = gst_caps_new_empty_simple ("audio/x-alac");
14185 _codec ("Free Lossless Audio Codec");
14186 caps = gst_caps_new_simple ("audio/x-flac",
14187 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14189 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
14190 _codec ("QualComm PureVoice");
14191 caps = gst_caps_from_string ("audio/qcelp");
14196 caps = gst_caps_new_empty_simple ("audio/x-wma");
14200 caps = gst_caps_new_empty_simple ("audio/x-opus");
14202 case GST_MAKE_FOURCC ('l', 'p', 'c', 'm'):
14207 GstAudioFormat format;
14210 FLAG_IS_FLOAT = 0x1,
14211 FLAG_IS_BIG_ENDIAN = 0x2,
14212 FLAG_IS_SIGNED = 0x4,
14213 FLAG_IS_PACKED = 0x8,
14214 FLAG_IS_ALIGNED_HIGH = 0x10,
14215 FLAG_IS_NON_INTERLEAVED = 0x20
14217 _codec ("Raw LPCM audio");
14219 if (data && len >= 56) {
14220 depth = QT_UINT32 (data + 40);
14221 flags = QT_UINT32 (data + 44);
14222 width = QT_UINT32 (data + 48) * 8 / entry->n_channels;
14224 if ((flags & FLAG_IS_FLOAT) == 0) {
14229 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
14230 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
14231 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
14232 caps = gst_caps_new_simple ("audio/x-raw",
14233 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14234 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
14235 "non-interleaved" : "interleaved", NULL);
14236 stream->alignment = GST_ROUND_UP_8 (depth);
14237 stream->alignment = round_up_pow2 (stream->alignment);
14242 if (flags & FLAG_IS_BIG_ENDIAN)
14243 format = GST_AUDIO_FORMAT_F64BE;
14245 format = GST_AUDIO_FORMAT_F64LE;
14247 if (flags & FLAG_IS_BIG_ENDIAN)
14248 format = GST_AUDIO_FORMAT_F32BE;
14250 format = GST_AUDIO_FORMAT_F32LE;
14252 caps = gst_caps_new_simple ("audio/x-raw",
14253 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14254 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
14255 "non-interleaved" : "interleaved", NULL);
14256 stream->alignment = width / 8;
14260 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
14264 caps = _get_unknown_codec_name ("audio", fourcc);
14270 GstCaps *templ_caps =
14271 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
14272 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
14273 gst_caps_unref (caps);
14274 gst_caps_unref (templ_caps);
14275 caps = intersection;
14278 /* enable clipping for raw audio streams */
14279 s = gst_caps_get_structure (caps, 0);
14280 name = gst_structure_get_name (s);
14281 if (g_str_has_prefix (name, "audio/x-raw")) {
14282 stream->need_clip = TRUE;
14283 stream->max_buffer_size = 4096 * entry->bytes_per_frame;
14284 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
14290 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14291 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14292 const guint8 * stsd_entry_data, gchar ** codec_name)
14296 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14300 _codec ("DVD subtitle");
14301 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
14302 stream->need_process = TRUE;
14305 _codec ("Quicktime timed text");
14308 _codec ("3GPP timed text");
14310 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
14312 /* actual text piece needs to be extracted */
14313 stream->need_process = TRUE;
14316 _codec ("XML subtitles");
14317 caps = gst_caps_new_empty_simple ("application/ttml+xml");
14321 caps = _get_unknown_codec_name ("text", fourcc);
14329 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14330 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14331 const guint8 * stsd_entry_data, gchar ** codec_name)
14337 _codec ("MPEG 1 video");
14338 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14339 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14349 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
14350 const gchar * system_id)
14354 if (!qtdemux->protection_system_ids)
14355 qtdemux->protection_system_ids =
14356 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
14357 /* Check whether we already have an entry for this system ID. */
14358 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
14359 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
14360 if (g_ascii_strcasecmp (system_id, id) == 0) {
14364 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
14365 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,