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 (200*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_description_index; /* index is 1-based */
418 guint32 def_sample_duration;
419 guint32 def_sample_size;
420 guint32 def_sample_flags;
424 /* stereoscopic video streams */
425 GstVideoMultiviewMode multiview_mode;
426 GstVideoMultiviewFlags multiview_flags;
428 /* protected streams */
430 guint32 protection_scheme_type;
431 guint32 protection_scheme_version;
432 gpointer protection_scheme_info; /* specific to the protection scheme */
433 GQueue protection_scheme_event_queue;
436 /* Contains properties and cryptographic info for a set of samples from a
437 * track protected using Common Encryption (cenc) */
438 struct _QtDemuxCencSampleSetInfo
440 GstStructure *default_properties;
442 /* @crypto_info holds one GstStructure per sample */
443 GPtrArray *crypto_info;
447 qt_demux_state_string (enum QtDemuxState state)
450 case QTDEMUX_STATE_INITIAL:
452 case QTDEMUX_STATE_HEADER:
454 case QTDEMUX_STATE_MOVIE:
456 case QTDEMUX_STATE_BUFFER_MDAT:
457 return "<BUFFER_MDAT>";
463 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
464 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
465 guint32 fourcc, GstByteReader * parser);
466 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
467 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
468 guint32 fourcc, GstByteReader * parser);
470 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
472 static GstStaticPadTemplate gst_qtdemux_sink_template =
473 GST_STATIC_PAD_TEMPLATE ("sink",
476 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
480 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
481 GST_STATIC_PAD_TEMPLATE ("video_%u",
484 GST_STATIC_CAPS_ANY);
486 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
487 GST_STATIC_PAD_TEMPLATE ("audio_%u",
490 GST_STATIC_CAPS_ANY);
492 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
493 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
496 GST_STATIC_CAPS_ANY);
498 #define gst_qtdemux_parent_class parent_class
499 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
501 static void gst_qtdemux_dispose (GObject * object);
504 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
505 GstClockTime media_time);
507 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
508 QtDemuxStream * str, gint64 media_offset);
511 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
512 static GstIndex *gst_qtdemux_get_index (GstElement * element);
514 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
515 GstStateChange transition);
516 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
517 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
518 GstObject * parent, GstPadMode mode, gboolean active);
520 static void gst_qtdemux_loop (GstPad * pad);
521 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
523 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
525 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
526 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
527 QtDemuxStream * stream);
528 static void gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
529 QtDemuxStream * stream);
530 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
533 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
534 const guint8 * buffer, guint length);
535 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
536 const guint8 * buffer, guint length);
537 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
538 static void qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist,
541 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
542 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, GNode * esds,
544 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
545 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
546 const guint8 * stsd_entry_data, gchar ** codec_name);
547 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
548 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
549 const guint8 * data, int len, gchar ** codec_name);
550 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
551 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
552 gchar ** codec_name);
553 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
554 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
555 const guint8 * stsd_entry_data, gchar ** codec_name);
557 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
558 QtDemuxStream * stream, guint32 n);
559 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
560 static void gst_qtdemux_stream_free (GstQTDemux * qtdemux,
561 QtDemuxStream * stream);
562 static void gst_qtdemux_stream_clear (GstQTDemux * qtdemux,
563 QtDemuxStream * stream);
564 static void gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int index);
565 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
566 static void qtdemux_do_allocation (GstQTDemux * qtdemux,
567 QtDemuxStream * stream);
568 static gboolean gst_qtdemux_activate_segment (GstQTDemux * qtdemux,
569 QtDemuxStream * stream, guint32 seg_idx, GstClockTime offset);
570 static gboolean gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux,
571 QtDemuxStream * stream, gint seg_idx, GstClockTime offset,
572 GstClockTime * _start, GstClockTime * _stop);
573 static void gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
574 QtDemuxStream * stream, gint segment_index, GstClockTime pos);
576 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
577 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
579 static gchar *qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes);
581 static GstStructure *qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
582 QtDemuxStream * stream, guint sample_index);
583 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
585 static void qtdemux_gst_structure_free (GstStructure * gststructure);
588 gst_qtdemux_class_init (GstQTDemuxClass * klass)
590 GObjectClass *gobject_class;
591 GstElementClass *gstelement_class;
593 gobject_class = (GObjectClass *) klass;
594 gstelement_class = (GstElementClass *) klass;
596 parent_class = g_type_class_peek_parent (klass);
598 gobject_class->dispose = gst_qtdemux_dispose;
600 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
602 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
603 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
606 gst_tag_register_musicbrainz_tags ();
608 gst_element_class_add_static_pad_template (gstelement_class,
609 &gst_qtdemux_sink_template);
610 gst_element_class_add_static_pad_template (gstelement_class,
611 &gst_qtdemux_videosrc_template);
612 gst_element_class_add_static_pad_template (gstelement_class,
613 &gst_qtdemux_audiosrc_template);
614 gst_element_class_add_static_pad_template (gstelement_class,
615 &gst_qtdemux_subsrc_template);
616 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
618 "Demultiplex a QuickTime file into audio and video streams",
619 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
621 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
626 gst_qtdemux_init (GstQTDemux * qtdemux)
629 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
630 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
631 gst_pad_set_activatemode_function (qtdemux->sinkpad,
632 qtdemux_sink_activate_mode);
633 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
634 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
635 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
637 qtdemux->state = QTDEMUX_STATE_INITIAL;
638 qtdemux->pullbased = FALSE;
639 qtdemux->posted_redirect = FALSE;
640 qtdemux->neededbytes = 16;
642 qtdemux->adapter = gst_adapter_new ();
644 qtdemux->first_mdat = -1;
645 qtdemux->got_moov = FALSE;
646 qtdemux->mdatoffset = -1;
647 qtdemux->mdatbuffer = NULL;
648 qtdemux->restoredata_buffer = NULL;
649 qtdemux->restoredata_offset = -1;
650 qtdemux->fragment_start = -1;
651 qtdemux->fragment_start_offset = -1;
652 qtdemux->media_caps = NULL;
653 qtdemux->exposed = FALSE;
654 qtdemux->mss_mode = FALSE;
655 qtdemux->pending_newsegment = NULL;
656 qtdemux->upstream_format_is_time = FALSE;
657 qtdemux->have_group_id = FALSE;
658 qtdemux->group_id = G_MAXUINT;
659 qtdemux->cenc_aux_info_offset = 0;
660 qtdemux->cenc_aux_info_sizes = NULL;
661 qtdemux->cenc_aux_sample_count = 0;
662 qtdemux->protection_system_ids = NULL;
663 g_queue_init (&qtdemux->protection_event_queue);
664 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
665 qtdemux->tag_list = gst_tag_list_new_empty ();
666 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
667 qtdemux->flowcombiner = gst_flow_combiner_new ();
669 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
673 gst_qtdemux_dispose (GObject * object)
675 GstQTDemux *qtdemux = GST_QTDEMUX (object);
677 if (qtdemux->adapter) {
678 g_object_unref (G_OBJECT (qtdemux->adapter));
679 qtdemux->adapter = NULL;
681 gst_tag_list_unref (qtdemux->tag_list);
682 gst_flow_combiner_free (qtdemux->flowcombiner);
683 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
685 g_queue_clear (&qtdemux->protection_event_queue);
687 g_free (qtdemux->cenc_aux_info_sizes);
688 qtdemux->cenc_aux_info_sizes = NULL;
690 G_OBJECT_CLASS (parent_class)->dispose (object);
694 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
696 if (qtdemux->posted_redirect) {
697 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
698 (_("This file contains no playable streams.")),
699 ("no known streams found, a redirect message has been posted"));
701 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
702 (_("This file contains no playable streams.")),
703 ("no known streams found"));
708 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
710 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
711 mem, size, 0, size, mem, free_func);
715 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
722 if (G_UNLIKELY (size == 0)) {
724 GstBuffer *tmp = NULL;
726 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
727 if (ret != GST_FLOW_OK)
730 gst_buffer_map (tmp, &map, GST_MAP_READ);
731 size = QT_UINT32 (map.data);
732 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
734 gst_buffer_unmap (tmp, &map);
735 gst_buffer_unref (tmp);
738 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
739 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
740 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
741 /* we're pulling header but already got most interesting bits,
742 * so never mind the rest (e.g. tags) (that much) */
743 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
747 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
748 (_("This file is invalid and cannot be played.")),
749 ("atom has bogus size %" G_GUINT64_FORMAT, size));
750 return GST_FLOW_ERROR;
754 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
756 if (G_UNLIKELY (flow != GST_FLOW_OK))
759 bsize = gst_buffer_get_size (*buf);
760 /* Catch short reads - we don't want any partial atoms */
761 if (G_UNLIKELY (bsize < size)) {
762 GST_WARNING_OBJECT (qtdemux,
763 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
764 gst_buffer_unref (*buf);
774 gst_qtdemux_src_convert (GstQTDemux * qtdemux, GstPad * pad,
775 GstFormat src_format, gint64 src_value, GstFormat dest_format,
779 QtDemuxStream *stream = gst_pad_get_element_private (pad);
782 if (stream->subtype != FOURCC_vide) {
787 switch (src_format) {
788 case GST_FORMAT_TIME:
789 switch (dest_format) {
790 case GST_FORMAT_BYTES:{
791 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
797 *dest_value = stream->samples[index].offset;
799 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
800 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
801 GST_TIME_ARGS (src_value), *dest_value);
809 case GST_FORMAT_BYTES:
810 switch (dest_format) {
811 case GST_FORMAT_TIME:{
813 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
822 QTSTREAMTIME_TO_GSTTIME (stream,
823 stream->samples[index].timestamp);
824 GST_DEBUG_OBJECT (qtdemux,
825 "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
826 GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
845 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
847 gboolean res = FALSE;
849 *duration = GST_CLOCK_TIME_NONE;
851 if (qtdemux->duration != 0 &&
852 qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
853 *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
856 *duration = GST_CLOCK_TIME_NONE;
863 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
866 gboolean res = FALSE;
867 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
869 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
871 switch (GST_QUERY_TYPE (query)) {
872 case GST_QUERY_POSITION:{
875 gst_query_parse_position (query, &fmt, NULL);
876 if (fmt == GST_FORMAT_TIME
877 && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
878 gst_query_set_position (query, GST_FORMAT_TIME,
879 qtdemux->segment.position);
884 case GST_QUERY_DURATION:{
887 gst_query_parse_duration (query, &fmt, NULL);
888 if (fmt == GST_FORMAT_TIME) {
889 /* First try to query upstream */
890 res = gst_pad_query_default (pad, parent, query);
892 GstClockTime duration;
893 if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
894 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
901 case GST_QUERY_CONVERT:{
902 GstFormat src_fmt, dest_fmt;
903 gint64 src_value, dest_value = 0;
905 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
907 res = gst_qtdemux_src_convert (qtdemux, pad,
908 src_fmt, src_value, dest_fmt, &dest_value);
910 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;
1628 guint32 seqnum = GST_SEQNUM_INVALID;
1629 GstEvent *flush_event;
1633 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1635 gst_event_parse_seek (event, &rate, &format, &flags,
1636 &cur_type, &cur, &stop_type, &stop);
1637 seqnum = gst_event_get_seqnum (event);
1639 /* we have to have a format as the segment format. Try to convert
1641 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1645 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1647 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1651 flush = flags & GST_SEEK_FLAG_FLUSH;
1653 /* stop streaming, either by flushing or by pausing the task */
1655 flush_event = gst_event_new_flush_start ();
1656 if (seqnum != GST_SEQNUM_INVALID)
1657 gst_event_set_seqnum (flush_event, seqnum);
1658 /* unlock upstream pull_range */
1659 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1660 /* make sure out loop function exits */
1661 gst_qtdemux_push_event (qtdemux, flush_event);
1663 /* non flushing seek, pause the task */
1664 gst_pad_pause_task (qtdemux->sinkpad);
1667 /* wait for streaming to finish */
1668 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1670 /* copy segment, we need this because we still need the old
1671 * segment when we close the current segment. */
1672 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1675 /* configure the segment with the seek variables */
1676 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1677 if (!gst_segment_do_seek (&seeksegment, rate, format, flags,
1678 cur_type, cur, stop_type, stop, &update)) {
1680 GST_ERROR_OBJECT (qtdemux, "inconsistent seek values, doing nothing");
1682 /* now do the seek */
1683 ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1686 /* now do the seek */
1687 ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1690 /* prepare for streaming again */
1692 flush_event = gst_event_new_flush_stop (TRUE);
1693 if (seqnum != GST_SEQNUM_INVALID)
1694 gst_event_set_seqnum (flush_event, seqnum);
1696 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1697 gst_qtdemux_push_event (qtdemux, flush_event);
1700 /* commit the new segment */
1701 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1703 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1704 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1705 qtdemux->segment.format, qtdemux->segment.position);
1706 if (seqnum != GST_SEQNUM_INVALID)
1707 gst_message_set_seqnum (msg, seqnum);
1708 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1711 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1712 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1713 qtdemux->sinkpad, NULL);
1715 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1722 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1728 qtdemux_ensure_index (GstQTDemux * qtdemux)
1732 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1734 /* Build complete index */
1735 for (i = 0; i < qtdemux->n_streams; i++) {
1736 QtDemuxStream *stream = qtdemux->streams[i];
1738 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1746 GST_LOG_OBJECT (qtdemux,
1747 "Building complete index of stream %u for seeking failed!", i);
1753 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1756 gboolean res = TRUE;
1757 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1759 switch (GST_EVENT_TYPE (event)) {
1760 case GST_EVENT_SEEK:
1762 #ifndef GST_DISABLE_GST_DEBUG
1763 GstClockTime ts = gst_util_get_timestamp ();
1765 guint32 seqnum = gst_event_get_seqnum (event);
1767 if (seqnum == qtdemux->segment_seqnum) {
1768 GST_LOG_OBJECT (pad,
1769 "Drop duplicated SEEK event seqnum %" G_GUINT32_FORMAT, seqnum);
1770 gst_event_unref (event);
1774 if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1775 /* seek should be handled by upstream, we might need to re-download fragments */
1776 GST_DEBUG_OBJECT (qtdemux,
1777 "let upstream handle seek for fragmented playback");
1781 /* Build complete index for seeking;
1782 * if not a fragmented file at least */
1783 if (!qtdemux->fragmented)
1784 if (!qtdemux_ensure_index (qtdemux))
1786 #ifndef GST_DISABLE_GST_DEBUG
1787 ts = gst_util_get_timestamp () - ts;
1788 GST_INFO_OBJECT (qtdemux,
1789 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1792 if (qtdemux->pullbased) {
1793 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1794 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1795 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1797 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams
1798 && !qtdemux->fragmented) {
1799 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1801 GST_DEBUG_OBJECT (qtdemux,
1802 "ignoring seek in push mode in current state");
1805 gst_event_unref (event);
1809 res = gst_pad_event_default (pad, parent, event);
1819 GST_ERROR_OBJECT (qtdemux, "Index failed");
1820 gst_event_unref (event);
1826 /* stream/index return sample that is min/max w.r.t. byte position,
1827 * time is min/max w.r.t. time of samples,
1828 * the latter need not be time of the former sample */
1830 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1831 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1834 gint64 time, min_time;
1835 QtDemuxStream *stream;
1841 for (n = 0; n < qtdemux->n_streams; ++n) {
1844 gboolean set_sample;
1846 str = qtdemux->streams[n];
1853 i = str->n_samples - 1;
1857 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1858 if (str->samples[i].size == 0)
1861 if (fw && (str->samples[i].offset < byte_pos))
1864 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1867 /* move stream to first available sample */
1869 gst_qtdemux_move_stream (qtdemux, str, i);
1873 /* avoid index from sparse streams since they might be far away */
1874 if (!CUR_STREAM (str)->sparse) {
1875 /* determine min/max time */
1876 time = QTSAMPLE_PTS (str, &str->samples[i]);
1877 if (min_time == -1 || (!fw && time > min_time) ||
1878 (fw && time < min_time)) {
1882 /* determine stream with leading sample, to get its position */
1884 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1885 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1893 /* no sample for this stream, mark eos */
1895 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1906 static QtDemuxStream *
1907 _create_stream (void)
1909 QtDemuxStream *stream;
1911 stream = g_new0 (QtDemuxStream, 1);
1912 /* new streams always need a discont */
1913 stream->discont = TRUE;
1914 /* we enable clipping for raw audio/video streams */
1915 stream->need_clip = FALSE;
1916 stream->need_process = FALSE;
1917 stream->segment_index = -1;
1918 stream->time_position = 0;
1919 stream->sample_index = -1;
1920 stream->offset_in_sample = 0;
1921 stream->new_stream = TRUE;
1922 stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1923 stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1924 stream->protected = FALSE;
1925 stream->protection_scheme_type = 0;
1926 stream->protection_scheme_version = 0;
1927 stream->protection_scheme_info = NULL;
1928 stream->n_samples_moof = 0;
1929 stream->duration_moof = 0;
1930 stream->duration_last_moof = 0;
1931 stream->alignment = 1;
1932 stream->stream_tags = gst_tag_list_new_empty ();
1933 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
1934 g_queue_init (&stream->protection_scheme_event_queue);
1939 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1941 GstStructure *structure;
1942 const gchar *variant;
1943 const GstCaps *mediacaps = NULL;
1945 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1947 structure = gst_caps_get_structure (caps, 0);
1948 variant = gst_structure_get_string (structure, "variant");
1950 if (variant && strcmp (variant, "mss-fragmented") == 0) {
1951 QtDemuxStream *stream;
1952 const GValue *value;
1954 demux->fragmented = TRUE;
1955 demux->mss_mode = TRUE;
1957 if (demux->n_streams > 1) {
1958 /* can't do this, we can only renegotiate for another mss format */
1962 value = gst_structure_get_value (structure, "media-caps");
1965 const GValue *timescale_v;
1967 /* TODO update when stream changes during playback */
1969 if (demux->n_streams == 0) {
1970 stream = _create_stream ();
1971 demux->streams[demux->n_streams] = stream;
1972 demux->n_streams = 1;
1973 /* mss has no stsd/stsd entry, use id 0 as default */
1974 stream->stsd_entries_length = 1;
1975 stream->stsd_sample_description_id = stream->cur_stsd_entry_index = 0;
1976 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, 1);
1978 stream = demux->streams[0];
1981 timescale_v = gst_structure_get_value (structure, "timescale");
1983 stream->timescale = g_value_get_uint64 (timescale_v);
1985 /* default mss timescale */
1986 stream->timescale = 10000000;
1988 demux->timescale = stream->timescale;
1990 mediacaps = gst_value_get_caps (value);
1991 if (!CUR_STREAM (stream)->caps
1992 || !gst_caps_is_equal_fixed (mediacaps, CUR_STREAM (stream)->caps)) {
1993 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1995 stream->new_caps = TRUE;
1997 gst_caps_replace (&CUR_STREAM (stream)->caps, (GstCaps *) mediacaps);
1998 structure = gst_caps_get_structure (mediacaps, 0);
1999 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
2000 stream->subtype = FOURCC_vide;
2002 gst_structure_get_int (structure, "width", &CUR_STREAM (stream)->width);
2003 gst_structure_get_int (structure, "height",
2004 &CUR_STREAM (stream)->height);
2005 gst_structure_get_fraction (structure, "framerate",
2006 &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
2007 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
2009 stream->subtype = FOURCC_soun;
2010 gst_structure_get_int (structure, "channels",
2011 &CUR_STREAM (stream)->n_channels);
2012 gst_structure_get_int (structure, "rate", &rate);
2013 CUR_STREAM (stream)->rate = rate;
2016 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
2018 demux->mss_mode = FALSE;
2025 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
2029 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
2030 gst_pad_stop_task (qtdemux->sinkpad);
2032 if (hard || qtdemux->upstream_format_is_time) {
2033 qtdemux->state = QTDEMUX_STATE_INITIAL;
2034 qtdemux->neededbytes = 16;
2035 qtdemux->todrop = 0;
2036 qtdemux->pullbased = FALSE;
2037 qtdemux->posted_redirect = FALSE;
2038 qtdemux->first_mdat = -1;
2039 qtdemux->header_size = 0;
2040 qtdemux->mdatoffset = -1;
2041 qtdemux->restoredata_offset = -1;
2042 if (qtdemux->mdatbuffer)
2043 gst_buffer_unref (qtdemux->mdatbuffer);
2044 if (qtdemux->restoredata_buffer)
2045 gst_buffer_unref (qtdemux->restoredata_buffer);
2046 qtdemux->mdatbuffer = NULL;
2047 qtdemux->restoredata_buffer = NULL;
2048 qtdemux->mdatleft = 0;
2049 qtdemux->mdatsize = 0;
2050 if (qtdemux->comp_brands)
2051 gst_buffer_unref (qtdemux->comp_brands);
2052 qtdemux->comp_brands = NULL;
2053 qtdemux->last_moov_offset = -1;
2054 if (qtdemux->moov_node_compressed) {
2055 g_node_destroy (qtdemux->moov_node_compressed);
2056 if (qtdemux->moov_node)
2057 g_free (qtdemux->moov_node->data);
2059 qtdemux->moov_node_compressed = NULL;
2060 if (qtdemux->moov_node)
2061 g_node_destroy (qtdemux->moov_node);
2062 qtdemux->moov_node = NULL;
2063 if (qtdemux->tag_list)
2064 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
2065 qtdemux->tag_list = gst_tag_list_new_empty ();
2066 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
2068 if (qtdemux->element_index)
2069 gst_object_unref (qtdemux->element_index);
2070 qtdemux->element_index = NULL;
2072 qtdemux->major_brand = 0;
2073 if (qtdemux->pending_newsegment)
2074 gst_event_unref (qtdemux->pending_newsegment);
2075 qtdemux->pending_newsegment = NULL;
2076 qtdemux->upstream_format_is_time = FALSE;
2077 qtdemux->upstream_seekable = FALSE;
2078 qtdemux->upstream_size = 0;
2080 qtdemux->fragment_start = -1;
2081 qtdemux->fragment_start_offset = -1;
2082 qtdemux->duration = 0;
2083 qtdemux->moof_offset = 0;
2084 qtdemux->chapters_track_id = 0;
2085 qtdemux->have_group_id = FALSE;
2086 qtdemux->group_id = G_MAXUINT;
2088 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
2090 g_queue_clear (&qtdemux->protection_event_queue);
2092 qtdemux->offset = 0;
2093 gst_adapter_clear (qtdemux->adapter);
2094 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
2095 qtdemux->segment_seqnum = GST_SEQNUM_INVALID;
2098 for (n = 0; n < qtdemux->n_streams; n++) {
2099 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
2100 qtdemux->streams[n] = NULL;
2102 qtdemux->n_streams = 0;
2103 qtdemux->n_video_streams = 0;
2104 qtdemux->n_audio_streams = 0;
2105 qtdemux->n_sub_streams = 0;
2106 qtdemux->exposed = FALSE;
2107 qtdemux->fragmented = FALSE;
2108 qtdemux->mss_mode = FALSE;
2109 gst_caps_replace (&qtdemux->media_caps, NULL);
2110 qtdemux->timescale = 0;
2111 qtdemux->got_moov = FALSE;
2112 if (qtdemux->protection_system_ids) {
2113 g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2114 qtdemux->protection_system_ids = NULL;
2116 } else if (qtdemux->mss_mode) {
2117 gst_flow_combiner_reset (qtdemux->flowcombiner);
2118 for (n = 0; n < qtdemux->n_streams; n++)
2119 gst_qtdemux_stream_clear (qtdemux, qtdemux->streams[n]);
2121 gst_flow_combiner_reset (qtdemux->flowcombiner);
2122 for (n = 0; n < qtdemux->n_streams; n++) {
2123 qtdemux->streams[n]->sent_eos = FALSE;
2124 qtdemux->streams[n]->time_position = 0;
2125 qtdemux->streams[n]->accumulated_base = 0;
2127 if (!qtdemux->pending_newsegment) {
2128 qtdemux->pending_newsegment = gst_event_new_segment (&qtdemux->segment);
2129 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
2130 gst_event_set_seqnum (qtdemux->pending_newsegment,
2131 qtdemux->segment_seqnum);
2137 /* Maps the @segment to the qt edts internal segments and pushes
2138 * the correspnding segment event.
2140 * If it ends up being at a empty segment, a gap will be pushed and the next
2141 * edts segment will be activated in sequence.
2143 * To be used in push-mode only */
2145 gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
2149 for (n = 0; n < qtdemux->n_streams; n++) {
2150 QtDemuxStream *stream = qtdemux->streams[n];
2152 stream->time_position = segment->start;
2154 /* in push mode we should be guaranteed that we will have empty segments
2155 * at the beginning and then one segment after, other scenarios are not
2156 * supported and are discarded when parsing the edts */
2157 for (i = 0; i < stream->n_segments; i++) {
2158 if (stream->segments[i].stop_time > segment->start) {
2159 gst_qtdemux_activate_segment (qtdemux, stream, i,
2160 stream->time_position);
2161 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
2162 /* push the empty segment and move to the next one */
2163 gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
2164 stream->time_position);
2168 g_assert (i == stream->n_segments - 1);
2175 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2178 GstQTDemux *demux = GST_QTDEMUX (parent);
2179 gboolean res = TRUE;
2181 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2183 switch (GST_EVENT_TYPE (event)) {
2184 case GST_EVENT_SEGMENT:
2187 QtDemuxStream *stream;
2191 /* some debug output */
2192 gst_event_copy_segment (event, &segment);
2193 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2196 /* erase any previously set segment */
2197 gst_event_replace (&demux->pending_newsegment, NULL);
2199 if (segment.format == GST_FORMAT_TIME) {
2200 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
2201 gst_event_replace (&demux->pending_newsegment, event);
2202 demux->upstream_format_is_time = TRUE;
2204 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2205 "not in time format");
2207 /* chain will send initial newsegment after pads have been added */
2208 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
2209 GST_DEBUG_OBJECT (demux, "still starting, eating event");
2214 /* check if this matches a time seek we received previously
2215 * FIXME for backwards compatibility reasons we use the
2216 * seek_offset here to compare. In the future we might want to
2217 * change this to use the seqnum as it uniquely should identify
2218 * the segment that corresponds to the seek. */
2219 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2220 ", received segment offset %" G_GINT64_FORMAT,
2221 demux->seek_offset, segment.start);
2222 if (segment.format == GST_FORMAT_BYTES
2223 && demux->seek_offset == segment.start) {
2224 GST_OBJECT_LOCK (demux);
2225 offset = segment.start;
2227 segment.format = GST_FORMAT_TIME;
2228 segment.start = demux->push_seek_start;
2229 segment.stop = demux->push_seek_stop;
2230 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2231 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2232 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2233 GST_OBJECT_UNLOCK (demux);
2236 /* we only expect a BYTE segment, e.g. following a seek */
2237 if (segment.format == GST_FORMAT_BYTES) {
2238 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2239 offset = segment.start;
2241 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2242 NULL, (gint64 *) & segment.start);
2243 if ((gint64) segment.start < 0)
2246 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2247 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2248 NULL, (gint64 *) & segment.stop);
2249 /* keyframe seeking should already arrange for start >= stop,
2250 * but make sure in other rare cases */
2251 segment.stop = MAX (segment.stop, segment.start);
2253 } else if (segment.format == GST_FORMAT_TIME) {
2254 /* push all data on the adapter before starting this
2256 gst_qtdemux_process_adapter (demux, TRUE);
2258 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2262 /* We shouldn't modify upstream driven TIME FORMAT segment */
2263 if (!demux->upstream_format_is_time) {
2264 /* accept upstream's notion of segment and distribute along */
2265 segment.format = GST_FORMAT_TIME;
2266 segment.position = segment.time = segment.start;
2267 segment.duration = demux->segment.duration;
2268 segment.base = gst_segment_to_running_time (&demux->segment,
2269 GST_FORMAT_TIME, demux->segment.position);
2272 gst_segment_copy_into (&segment, &demux->segment);
2273 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2275 /* map segment to internal qt segments and push on each stream */
2276 if (demux->n_streams) {
2277 if (demux->fragmented) {
2278 GstEvent *segment_event = gst_event_new_segment (&segment);
2280 gst_event_replace (&demux->pending_newsegment, NULL);
2281 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
2282 gst_qtdemux_push_event (demux, segment_event);
2284 gst_event_replace (&demux->pending_newsegment, NULL);
2285 gst_qtdemux_map_and_push_segments (demux, &segment);
2289 /* clear leftover in current segment, if any */
2290 gst_adapter_clear (demux->adapter);
2292 /* set up streaming thread */
2293 demux->offset = offset;
2294 if (demux->upstream_format_is_time) {
2295 GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2296 "set values to restart reading from a new atom");
2297 demux->neededbytes = 16;
2300 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2303 demux->todrop = stream->samples[idx].offset - offset;
2304 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2306 /* set up for EOS */
2307 demux->neededbytes = -1;
2312 gst_event_unref (event);
2316 case GST_EVENT_FLUSH_START:
2318 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2319 gst_event_unref (event);
2324 case GST_EVENT_FLUSH_STOP:
2328 dur = demux->segment.duration;
2329 gst_qtdemux_reset (demux, FALSE);
2330 demux->segment.duration = dur;
2332 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2333 gst_event_unref (event);
2339 /* If we are in push mode, and get an EOS before we've seen any streams,
2340 * then error out - we have nowhere to send the EOS */
2341 if (!demux->pullbased) {
2343 gboolean has_valid_stream = FALSE;
2344 for (i = 0; i < demux->n_streams; i++) {
2345 if (demux->streams[i]->pad != NULL) {
2346 has_valid_stream = TRUE;
2350 if (!has_valid_stream)
2351 gst_qtdemux_post_no_playable_stream_error (demux);
2353 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2354 (guint) gst_adapter_available (demux->adapter));
2355 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2361 case GST_EVENT_CAPS:{
2362 GstCaps *caps = NULL;
2364 gst_event_parse_caps (event, &caps);
2365 gst_qtdemux_setcaps (demux, caps);
2367 gst_event_unref (event);
2370 case GST_EVENT_PROTECTION:
2372 const gchar *system_id = NULL;
2374 gst_event_parse_protection (event, &system_id, NULL, NULL);
2375 GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2377 gst_qtdemux_append_protection_system_id (demux, system_id);
2378 /* save the event for later, for source pads that have not been created */
2379 g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2380 /* send it to all pads that already exist */
2381 gst_qtdemux_push_event (demux, event);
2389 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2397 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2399 GstQTDemux *demux = GST_QTDEMUX (element);
2401 GST_OBJECT_LOCK (demux);
2402 if (demux->element_index)
2403 gst_object_unref (demux->element_index);
2405 demux->element_index = gst_object_ref (index);
2407 demux->element_index = NULL;
2409 GST_OBJECT_UNLOCK (demux);
2410 /* object lock might be taken again */
2412 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2413 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2414 demux->element_index, demux->index_id);
2418 gst_qtdemux_get_index (GstElement * element)
2420 GstIndex *result = NULL;
2421 GstQTDemux *demux = GST_QTDEMUX (element);
2423 GST_OBJECT_LOCK (demux);
2424 if (demux->element_index)
2425 result = gst_object_ref (demux->element_index);
2426 GST_OBJECT_UNLOCK (demux);
2428 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2435 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2437 g_free ((gpointer) stream->stco.data);
2438 stream->stco.data = NULL;
2439 g_free ((gpointer) stream->stsz.data);
2440 stream->stsz.data = NULL;
2441 g_free ((gpointer) stream->stsc.data);
2442 stream->stsc.data = NULL;
2443 g_free ((gpointer) stream->stts.data);
2444 stream->stts.data = NULL;
2445 g_free ((gpointer) stream->stss.data);
2446 stream->stss.data = NULL;
2447 g_free ((gpointer) stream->stps.data);
2448 stream->stps.data = NULL;
2449 g_free ((gpointer) stream->ctts.data);
2450 stream->ctts.data = NULL;
2454 gst_qtdemux_stream_flush_segments_data (GstQTDemux * qtdemux,
2455 QtDemuxStream * stream)
2457 g_free (stream->segments);
2458 stream->segments = NULL;
2459 stream->segment_index = -1;
2460 stream->accumulated_base = 0;
2464 gst_qtdemux_stream_flush_samples_data (GstQTDemux * qtdemux,
2465 QtDemuxStream * stream)
2467 g_free (stream->samples);
2468 stream->samples = NULL;
2469 gst_qtdemux_stbl_free (stream);
2472 g_free (stream->ra_entries);
2473 stream->ra_entries = NULL;
2474 stream->n_ra_entries = 0;
2476 stream->sample_index = -1;
2477 stream->stbl_index = -1;
2478 stream->n_samples = 0;
2479 stream->time_position = 0;
2481 stream->n_samples_moof = 0;
2482 stream->duration_moof = 0;
2483 stream->duration_last_moof = 0;
2487 gst_qtdemux_stream_clear (GstQTDemux * qtdemux, QtDemuxStream * stream)
2490 if (stream->allocator)
2491 gst_object_unref (stream->allocator);
2492 while (stream->buffers) {
2493 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2494 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2496 for (i = 0; i < stream->stsd_entries_length; i++) {
2497 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2498 if (entry->rgb8_palette) {
2499 gst_memory_unref (entry->rgb8_palette);
2500 entry->rgb8_palette = NULL;
2502 entry->sparse = FALSE;
2505 gst_tag_list_unref (stream->stream_tags);
2506 stream->stream_tags = gst_tag_list_new_empty ();
2507 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
2508 g_free (stream->redirect_uri);
2509 stream->redirect_uri = NULL;
2510 stream->sent_eos = FALSE;
2511 stream->protected = FALSE;
2512 if (stream->protection_scheme_info) {
2513 if (stream->protection_scheme_type == FOURCC_cenc) {
2514 QtDemuxCencSampleSetInfo *info =
2515 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2516 if (info->default_properties)
2517 gst_structure_free (info->default_properties);
2518 if (info->crypto_info)
2519 g_ptr_array_free (info->crypto_info, TRUE);
2521 g_free (stream->protection_scheme_info);
2522 stream->protection_scheme_info = NULL;
2524 stream->protection_scheme_type = 0;
2525 stream->protection_scheme_version = 0;
2526 g_queue_foreach (&stream->protection_scheme_event_queue,
2527 (GFunc) gst_event_unref, NULL);
2528 g_queue_clear (&stream->protection_scheme_event_queue);
2529 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
2530 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
2534 gst_qtdemux_stream_reset (GstQTDemux * qtdemux, QtDemuxStream * stream)
2537 gst_qtdemux_stream_clear (qtdemux, stream);
2538 for (i = 0; i < stream->stsd_entries_length; i++) {
2539 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2541 gst_caps_unref (entry->caps);
2545 g_free (stream->stsd_entries);
2546 stream->stsd_entries = NULL;
2547 stream->stsd_entries_length = 0;
2552 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
2554 gst_qtdemux_stream_reset (qtdemux, stream);
2555 gst_tag_list_unref (stream->stream_tags);
2557 gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
2558 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, stream->pad);
2564 gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int i)
2566 g_assert (i >= 0 && i < qtdemux->n_streams && qtdemux->streams[i] != NULL);
2568 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[i]);
2569 qtdemux->streams[i] = qtdemux->streams[qtdemux->n_streams - 1];
2570 qtdemux->streams[qtdemux->n_streams - 1] = NULL;
2571 qtdemux->n_streams--;
2574 static GstStateChangeReturn
2575 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2577 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2578 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2580 switch (transition) {
2581 case GST_STATE_CHANGE_PAUSED_TO_READY:
2587 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2589 switch (transition) {
2590 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2591 gst_qtdemux_reset (qtdemux, TRUE);
2602 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2604 /* counts as header data */
2605 qtdemux->header_size += length;
2607 /* only consider at least a sufficiently complete ftyp atom */
2611 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2612 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2613 GST_FOURCC_ARGS (qtdemux->major_brand));
2614 if (qtdemux->comp_brands)
2615 gst_buffer_unref (qtdemux->comp_brands);
2616 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2617 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2622 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist,
2623 GstTagList * xmptaglist)
2625 /* Strip out bogus fields */
2627 if (gst_tag_list_get_scope (taglist) == GST_TAG_SCOPE_GLOBAL) {
2628 gst_tag_list_remove_tag (xmptaglist, GST_TAG_VIDEO_CODEC);
2629 gst_tag_list_remove_tag (xmptaglist, GST_TAG_AUDIO_CODEC);
2631 gst_tag_list_remove_tag (xmptaglist, GST_TAG_CONTAINER_FORMAT);
2634 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, xmptaglist);
2636 /* prioritize native tags using _KEEP mode */
2637 gst_tag_list_insert (taglist, xmptaglist, GST_TAG_MERGE_KEEP);
2638 gst_tag_list_unref (xmptaglist);
2643 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
2651 QtDemuxStream *stream;
2652 GstStructure *structure;
2653 QtDemuxCencSampleSetInfo *ss_info = NULL;
2654 const gchar *system_id;
2655 gboolean uses_sub_sample_encryption = FALSE;
2657 if (qtdemux->n_streams == 0)
2660 stream = qtdemux->streams[0];
2662 structure = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
2663 if (!gst_structure_has_name (structure, "application/x-cenc")) {
2664 GST_WARNING_OBJECT (qtdemux,
2665 "Attempting PIFF box parsing on an unencrypted stream.");
2669 gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
2670 G_TYPE_STRING, &system_id, NULL);
2671 gst_qtdemux_append_protection_system_id (qtdemux, system_id);
2673 stream->protected = TRUE;
2674 stream->protection_scheme_type = FOURCC_cenc;
2676 if (!stream->protection_scheme_info)
2677 stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
2679 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2681 if (ss_info->default_properties)
2682 gst_structure_free (ss_info->default_properties);
2684 ss_info->default_properties =
2685 gst_structure_new ("application/x-cenc",
2686 "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE, NULL);
2688 if (ss_info->crypto_info) {
2689 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
2690 g_ptr_array_free (ss_info->crypto_info, TRUE);
2691 ss_info->crypto_info = NULL;
2695 gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
2697 if (!gst_byte_reader_get_uint8 (&br, &version)) {
2698 GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
2702 if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
2703 GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
2707 if ((flags & 0x000001)) {
2708 guint32 algorithm_id = 0;
2711 gboolean is_encrypted = TRUE;
2713 if (!gst_byte_reader_get_uint24_le (&br, &algorithm_id)) {
2714 GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
2719 if (algorithm_id == 0) {
2720 is_encrypted = FALSE;
2721 } else if (algorithm_id == 1) {
2722 /* FIXME: maybe store this in properties? */
2723 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
2724 } else if (algorithm_id == 2) {
2725 /* FIXME: maybe store this in properties? */
2726 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
2729 if (!gst_byte_reader_get_uint8 (&br, &iv_size))
2732 if (!gst_byte_reader_get_data (&br, 16, &kid))
2735 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
2736 gst_buffer_fill (kid_buf, 0, kid, 16);
2737 if (ss_info->default_properties)
2738 gst_structure_free (ss_info->default_properties);
2739 ss_info->default_properties =
2740 gst_structure_new ("application/x-cenc",
2741 "iv_size", G_TYPE_UINT, iv_size,
2742 "encrypted", G_TYPE_BOOLEAN, is_encrypted,
2743 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
2744 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
2745 "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
2746 gst_buffer_unref (kid_buf);
2747 } else if ((flags & 0x000002)) {
2748 uses_sub_sample_encryption = TRUE;
2751 if (!gst_byte_reader_get_uint32_be (&br, &qtdemux->cenc_aux_sample_count)) {
2752 GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
2756 ss_info->crypto_info =
2757 g_ptr_array_new_full (qtdemux->cenc_aux_sample_count,
2758 (GDestroyNotify) qtdemux_gst_structure_free);
2760 for (i = 0; i < qtdemux->cenc_aux_sample_count; ++i) {
2761 GstStructure *properties;
2765 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
2766 if (properties == NULL) {
2767 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
2771 if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
2772 GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
2773 gst_structure_free (properties);
2776 buf = gst_buffer_new_wrapped (data, iv_size);
2777 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
2778 gst_buffer_unref (buf);
2780 if (uses_sub_sample_encryption) {
2781 guint16 n_subsamples;
2783 if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
2784 || n_subsamples == 0) {
2785 GST_ERROR_OBJECT (qtdemux,
2786 "failed to get subsample count for sample %u", i);
2787 gst_structure_free (properties);
2790 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
2791 if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
2792 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
2794 gst_structure_free (properties);
2797 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
2798 gst_structure_set (properties,
2799 "subsample_count", G_TYPE_UINT, n_subsamples,
2800 "subsamples", GST_TYPE_BUFFER, buf, NULL);
2801 gst_buffer_unref (buf);
2803 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
2806 g_ptr_array_add (ss_info->crypto_info, properties);
2811 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2813 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2814 0x97, 0xA9, 0x42, 0xE8,
2815 0x9C, 0x71, 0x99, 0x94,
2816 0x91, 0xE3, 0xAF, 0xAC
2818 static const guint8 playready_uuid[] = {
2819 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2820 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2823 static const guint8 piff_sample_encryption_uuid[] = {
2824 0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
2825 0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
2830 /* counts as header data */
2831 qtdemux->header_size += length;
2833 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2835 if (length <= offset + 16) {
2836 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2840 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2842 GstTagList *taglist;
2844 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2845 length - offset - 16, NULL);
2846 taglist = gst_tag_list_from_xmp_buffer (buf);
2847 gst_buffer_unref (buf);
2849 /* make sure we have a usable taglist */
2850 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
2852 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
2854 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
2856 const gunichar2 *s_utf16;
2859 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
2860 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
2861 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
2862 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
2866 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
2867 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
2869 } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
2870 qtdemux_parse_piff (qtdemux, buffer, length, offset);
2872 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
2873 GST_READ_UINT32_LE (buffer + offset),
2874 GST_READ_UINT32_LE (buffer + offset + 4),
2875 GST_READ_UINT32_LE (buffer + offset + 8),
2876 GST_READ_UINT32_LE (buffer + offset + 12));
2881 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2883 GstSidxParser sidx_parser;
2884 GstIsoffParserResult res;
2887 gst_isoff_qt_sidx_parser_init (&sidx_parser);
2890 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
2892 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
2893 if (res == GST_ISOFF_QT_PARSER_DONE) {
2894 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
2896 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
2899 /* caller verifies at least 8 bytes in buf */
2901 extract_initial_length_and_fourcc (const guint8 * data, guint size,
2902 guint64 * plength, guint32 * pfourcc)
2907 length = QT_UINT32 (data);
2908 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2909 fourcc = QT_FOURCC (data + 4);
2910 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
2913 length = G_MAXUINT64;
2914 } else if (length == 1 && size >= 16) {
2915 /* this means we have an extended size, which is the 64 bit value of
2916 * the next 8 bytes */
2917 length = QT_UINT64 (data + 8);
2918 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2928 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
2930 guint32 version = 0;
2931 GstClockTime duration = 0;
2933 if (!gst_byte_reader_get_uint32_be (br, &version))
2938 if (!gst_byte_reader_get_uint64_be (br, &duration))
2943 if (!gst_byte_reader_get_uint32_be (br, &dur))
2948 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
2949 qtdemux->duration = duration;
2955 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
2961 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
2962 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
2964 if (!stream->parsed_trex && qtdemux->moov_node) {
2966 GstByteReader trex_data;
2968 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
2970 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
2973 guint32 id = 0, sdi = 0, dur = 0, size = 0, flags = 0;
2975 /* skip version/flags */
2976 if (!gst_byte_reader_skip (&trex_data, 4))
2978 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
2980 if (id != stream->track_id)
2982 if (!gst_byte_reader_get_uint32_be (&trex_data, &sdi))
2984 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2986 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
2988 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
2991 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
2992 "duration %d, size %d, flags 0x%x", stream->track_id,
2995 stream->parsed_trex = TRUE;
2996 stream->def_sample_description_index = sdi;
2997 stream->def_sample_duration = dur;
2998 stream->def_sample_size = size;
2999 stream->def_sample_flags = flags;
3002 /* iterate all siblings */
3003 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
3009 *ds_duration = stream->def_sample_duration;
3010 *ds_size = stream->def_sample_size;
3011 *ds_flags = stream->def_sample_flags;
3013 /* even then, above values are better than random ... */
3014 if (G_UNLIKELY (!stream->parsed_trex)) {
3015 GST_WARNING_OBJECT (qtdemux,
3016 "failed to find fragment defaults for stream %d", stream->track_id);
3023 /* This method should be called whenever a more accurate duration might
3024 * have been found. It will update all relevant variables if/where needed
3027 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
3031 GstClockTime prevdur;
3033 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
3035 if (movdur > qtdemux->duration) {
3036 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
3037 GST_DEBUG_OBJECT (qtdemux,
3038 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
3039 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
3040 qtdemux->duration = movdur;
3041 GST_DEBUG_OBJECT (qtdemux,
3042 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
3043 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
3044 GST_TIME_ARGS (qtdemux->segment.stop));
3045 if (qtdemux->segment.duration == prevdur) {
3046 /* If the current segment has duration/stop identical to previous duration
3047 * update them also (because they were set at that point in time with
3048 * the wrong duration */
3049 /* We convert the value *from* the timescale version to avoid rounding errors */
3050 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
3051 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
3052 qtdemux->segment.duration = fixeddur;
3053 qtdemux->segment.stop = fixeddur;
3056 for (i = 0; i < qtdemux->n_streams; i++) {
3057 QtDemuxStream *stream = qtdemux->streams[i];
3059 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
3060 if (movdur > stream->duration) {
3061 GST_DEBUG_OBJECT (qtdemux,
3062 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
3063 GST_TIME_ARGS (duration));
3064 stream->duration = movdur;
3065 /* internal duration tracking state has been updated above, so */
3066 /* preserve an open-ended dummy segment rather than repeatedly updating
3067 * it and spamming downstream accordingly with segment events */
3068 if (stream->dummy_segment &&
3069 GST_CLOCK_TIME_IS_VALID (stream->segments[0].duration)) {
3070 /* Update all dummy values to new duration */
3071 stream->segments[0].stop_time = duration;
3072 stream->segments[0].duration = duration;
3073 stream->segments[0].media_stop = duration;
3075 /* let downstream know we possibly have a new stop time */
3076 if (stream->segment_index != -1) {
3079 if (qtdemux->segment.rate >= 0) {
3080 pos = stream->segment.start;
3082 pos = stream->segment.stop;
3085 gst_qtdemux_stream_update_segment (qtdemux, stream,
3086 stream->segment_index, pos, NULL, NULL);
3095 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
3096 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
3097 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
3098 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts,
3101 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
3103 gint32 data_offset = 0;
3104 guint32 flags = 0, first_flags = 0, samples_count = 0;
3107 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
3108 QtDemuxSample *sample;
3109 gboolean ismv = FALSE;
3110 gint64 initial_offset;
3112 GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
3113 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
3114 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
3115 d_sample_size, d_sample_flags, *base_offset, decode_ts);
3117 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
3118 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
3122 /* presence of stss or not can't really tell us much,
3123 * and flags and so on tend to be marginally reliable in these files */
3124 if (stream->subtype == FOURCC_soun) {
3125 GST_DEBUG_OBJECT (qtdemux,
3126 "sound track in fragmented file; marking all keyframes");
3127 stream->all_keyframe = TRUE;
3130 if (!gst_byte_reader_skip (trun, 1) ||
3131 !gst_byte_reader_get_uint24_be (trun, &flags))
3134 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3137 if (flags & TR_DATA_OFFSET) {
3138 /* note this is really signed */
3139 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3141 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3142 /* default base offset = first byte of moof */
3143 if (*base_offset == -1) {
3144 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3145 *base_offset = moof_offset;
3147 *running_offset = *base_offset + data_offset;
3149 /* if no offset at all, that would mean data starts at moof start,
3150 * which is a bit wrong and is ismv crappy way, so compensate
3151 * assuming data is in mdat following moof */
3152 if (*base_offset == -1) {
3153 *base_offset = moof_offset + moof_length + 8;
3154 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3157 if (*running_offset == -1)
3158 *running_offset = *base_offset;
3161 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3163 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3164 data_offset, flags, samples_count);
3166 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3167 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3168 GST_DEBUG_OBJECT (qtdemux,
3169 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3170 flags ^= TR_FIRST_SAMPLE_FLAGS;
3172 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3174 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3178 /* FIXME ? spec says other bits should also be checked to determine
3179 * entry size (and prefix size for that matter) */
3181 dur_offset = size_offset = 0;
3182 if (flags & TR_SAMPLE_DURATION) {
3183 GST_LOG_OBJECT (qtdemux, "entry duration present");
3184 dur_offset = entry_size;
3187 if (flags & TR_SAMPLE_SIZE) {
3188 GST_LOG_OBJECT (qtdemux, "entry size present");
3189 size_offset = entry_size;
3192 if (flags & TR_SAMPLE_FLAGS) {
3193 GST_LOG_OBJECT (qtdemux, "entry flags present");
3194 flags_offset = entry_size;
3197 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3198 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3199 ct_offset = entry_size;
3203 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3205 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3207 if (stream->n_samples + samples_count >=
3208 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3211 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3212 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3213 (stream->n_samples + samples_count) *
3214 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3216 /* create a new array of samples if it's the first sample parsed */
3217 if (stream->n_samples == 0) {
3218 g_assert (stream->samples == NULL);
3219 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3220 /* or try to reallocate it with space enough to insert the new samples */
3222 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3223 stream->n_samples + samples_count);
3224 if (stream->samples == NULL)
3227 if (qtdemux->fragment_start != -1) {
3228 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3229 qtdemux->fragment_start = -1;
3231 if (stream->n_samples == 0) {
3232 if (decode_ts > 0) {
3233 timestamp = decode_ts;
3234 } else if (stream->pending_seek != NULL) {
3235 /* if we don't have a timestamp from a tfdt box, we'll use the one
3236 * from the mfra seek table */
3237 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3238 GST_TIME_ARGS (stream->pending_seek->ts));
3240 /* FIXME: this is not fully correct, the timestamp refers to the random
3241 * access sample refered to in the tfra entry, which may not necessarily
3242 * be the first sample in the tfrag/trun (but hopefully/usually is) */
3243 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3248 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3249 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3250 GST_TIME_ARGS (gst_ts));
3252 /* subsequent fragments extend stream */
3254 stream->samples[stream->n_samples - 1].timestamp +
3255 stream->samples[stream->n_samples - 1].duration;
3257 /* If this is a GST_FORMAT_BYTES stream and there's a significant
3258 * difference (1 sec.) between decode_ts and timestamp, prefer the
3260 if (has_tfdt && !qtdemux->upstream_format_is_time
3261 && ABSDIFF (decode_ts, timestamp) >
3262 MAX (stream->duration_last_moof / 2,
3263 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) {
3264 GST_INFO_OBJECT (qtdemux,
3265 "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT
3266 ") are significantly different (more than %" GST_TIME_FORMAT
3267 "), using decode_ts",
3268 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)),
3269 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)),
3270 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
3271 MAX (stream->duration_last_moof / 2,
3272 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND)))));
3273 timestamp = decode_ts;
3276 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3277 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3278 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3282 initial_offset = *running_offset;
3284 sample = stream->samples + stream->n_samples;
3285 for (i = 0; i < samples_count; i++) {
3286 guint32 dur, size, sflags, ct;
3288 /* first read sample data */
3289 if (flags & TR_SAMPLE_DURATION) {
3290 dur = QT_UINT32 (data + dur_offset);
3292 dur = d_sample_duration;
3294 if (flags & TR_SAMPLE_SIZE) {
3295 size = QT_UINT32 (data + size_offset);
3297 size = d_sample_size;
3299 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3301 sflags = first_flags;
3303 sflags = d_sample_flags;
3305 } else if (flags & TR_SAMPLE_FLAGS) {
3306 sflags = QT_UINT32 (data + flags_offset);
3308 sflags = d_sample_flags;
3310 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3311 ct = QT_UINT32 (data + ct_offset);
3317 /* fill the sample information */
3318 sample->offset = *running_offset;
3319 sample->pts_offset = ct;
3320 sample->size = size;
3321 sample->timestamp = timestamp;
3322 sample->duration = dur;
3323 /* sample-is-difference-sample */
3324 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3325 * now idea how it relates to bitfield other than massive LE/BE confusion */
3326 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3327 *running_offset += size;
3329 stream->duration_moof += dur;
3333 /* Update total duration if needed */
3334 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3336 /* Pre-emptively figure out size of mdat based on trun information.
3337 * If the [mdat] atom is effectivelly read, it will be replaced by the actual
3338 * size, else we will still be able to use this when dealing with gap'ed
3340 qtdemux->mdatleft = *running_offset - initial_offset;
3341 qtdemux->mdatoffset = initial_offset;
3342 qtdemux->mdatsize = qtdemux->mdatleft;
3344 stream->n_samples += samples_count;
3345 stream->n_samples_moof += samples_count;
3347 if (stream->pending_seek != NULL)
3348 stream->pending_seek = NULL;
3354 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3359 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3365 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3366 "be larger than %uMB (broken file?)", stream->n_samples,
3367 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3372 /* find stream with @id */
3373 static inline QtDemuxStream *
3374 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3376 QtDemuxStream *stream;
3380 if (G_UNLIKELY (!id)) {
3381 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3385 /* try to get it fast and simple */
3386 if (G_LIKELY (id <= qtdemux->n_streams)) {
3387 stream = qtdemux->streams[id - 1];
3388 if (G_LIKELY (stream->track_id == id))
3392 /* linear search otherwise */
3393 for (i = 0; i < qtdemux->n_streams; i++) {
3394 stream = qtdemux->streams[i];
3395 if (stream->track_id == id)
3398 if (qtdemux->mss_mode) {
3399 /* mss should have only 1 stream anyway */
3400 return qtdemux->streams[0];
3407 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3408 guint32 * fragment_number)
3410 if (!gst_byte_reader_skip (mfhd, 4))
3412 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3417 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3423 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3424 QtDemuxStream ** stream, guint32 * default_sample_duration,
3425 guint32 * default_sample_size, guint32 * default_sample_flags,
3426 gint64 * base_offset)
3429 guint32 track_id = 0;
3431 if (!gst_byte_reader_skip (tfhd, 1) ||
3432 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3435 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3438 *stream = qtdemux_find_stream (qtdemux, track_id);
3439 if (G_UNLIKELY (!*stream))
3440 goto unknown_stream;
3442 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3443 *base_offset = qtdemux->moof_offset;
3445 if (flags & TF_BASE_DATA_OFFSET)
3446 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3449 /* obtain stream defaults */
3450 qtdemux_parse_trex (qtdemux, *stream,
3451 default_sample_duration, default_sample_size, default_sample_flags);
3453 (*stream)->stsd_sample_description_id =
3454 (*stream)->def_sample_description_index - 1;
3456 if (flags & TF_SAMPLE_DESCRIPTION_INDEX) {
3457 guint32 sample_description_index;
3458 if (!gst_byte_reader_get_uint32_be (tfhd, &sample_description_index))
3460 (*stream)->stsd_sample_description_id = sample_description_index - 1;
3463 if (qtdemux->mss_mode) {
3464 /* mss has no stsd entry */
3465 (*stream)->stsd_sample_description_id = 0;
3468 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3469 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3472 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3473 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3476 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3477 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3484 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3489 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
3495 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3496 guint64 * decode_time)
3498 guint32 version = 0;
3500 if (!gst_byte_reader_get_uint32_be (br, &version))
3505 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3508 guint32 dec_time = 0;
3509 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3511 *decode_time = dec_time;
3514 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3521 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3526 /* Returns a pointer to a GstStructure containing the properties of
3527 * the stream sample identified by @sample_index. The caller must unref
3528 * the returned object after use. Returns NULL if unsuccessful. */
3529 static GstStructure *
3530 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3531 QtDemuxStream * stream, guint sample_index)
3533 QtDemuxCencSampleSetInfo *info = NULL;
3535 g_return_val_if_fail (stream != NULL, NULL);
3536 g_return_val_if_fail (stream->protected, NULL);
3537 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3539 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3541 /* Currently, cenc properties for groups of samples are not supported, so
3542 * simply return a copy of the default sample properties */
3543 return gst_structure_copy (info->default_properties);
3546 /* Parses the sizes of sample auxiliary information contained within a stream,
3547 * as given in a saiz box. Returns array of sample_count guint8 size values,
3548 * or NULL on failure */
3550 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3551 GstByteReader * br, guint32 * sample_count)
3555 guint8 default_info_size;
3557 g_return_val_if_fail (qtdemux != NULL, NULL);
3558 g_return_val_if_fail (stream != NULL, NULL);
3559 g_return_val_if_fail (br != NULL, NULL);
3560 g_return_val_if_fail (sample_count != NULL, NULL);
3562 if (!gst_byte_reader_get_uint32_be (br, &flags))
3566 /* aux_info_type and aux_info_type_parameter are ignored */
3567 if (!gst_byte_reader_skip (br, 8))
3571 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3573 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3575 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3577 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3580 if (default_info_size == 0) {
3581 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3585 info_sizes = g_new (guint8, *sample_count);
3586 memset (info_sizes, default_info_size, *sample_count);
3592 /* Parses the offset of sample auxiliary information contained within a stream,
3593 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3595 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3596 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3601 guint32 aux_info_type = 0;
3602 guint32 aux_info_type_parameter = 0;
3603 guint32 entry_count;
3606 const guint8 *aux_info_type_data = NULL;
3608 g_return_val_if_fail (qtdemux != NULL, FALSE);
3609 g_return_val_if_fail (stream != NULL, FALSE);
3610 g_return_val_if_fail (br != NULL, FALSE);
3611 g_return_val_if_fail (offset != NULL, FALSE);
3613 if (!gst_byte_reader_get_uint8 (br, &version))
3616 if (!gst_byte_reader_get_uint24_be (br, &flags))
3621 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3623 aux_info_type = QT_FOURCC (aux_info_type_data);
3625 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3627 } else if (stream->protected) {
3628 aux_info_type = stream->protection_scheme_type;
3630 aux_info_type = CUR_STREAM (stream)->fourcc;
3634 *info_type = aux_info_type;
3635 if (info_type_parameter)
3636 *info_type_parameter = aux_info_type_parameter;
3638 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3639 "aux_info_type_parameter: %#06x",
3640 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3642 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3645 if (entry_count != 1) {
3646 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3651 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3653 *offset = (guint64) off_32;
3655 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3660 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3665 qtdemux_gst_structure_free (GstStructure * gststructure)
3668 gst_structure_free (gststructure);
3672 /* Parses auxiliary information relating to samples protected using Common
3673 * Encryption (cenc); the format of this information is defined in
3674 * ISO/IEC 23001-7. Returns TRUE if successful; FALSE otherwise. */
3676 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3677 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3679 QtDemuxCencSampleSetInfo *ss_info = NULL;
3682 GPtrArray *old_crypto_info = NULL;
3683 guint old_entries = 0;
3685 g_return_val_if_fail (qtdemux != NULL, FALSE);
3686 g_return_val_if_fail (stream != NULL, FALSE);
3687 g_return_val_if_fail (br != NULL, FALSE);
3688 g_return_val_if_fail (stream->protected, FALSE);
3689 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3691 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3693 if (ss_info->crypto_info) {
3694 old_crypto_info = ss_info->crypto_info;
3695 /* Count number of non-null entries remaining at the tail end */
3696 for (i = old_crypto_info->len - 1; i >= 0; i--) {
3697 if (g_ptr_array_index (old_crypto_info, i) == NULL)
3703 ss_info->crypto_info =
3704 g_ptr_array_new_full (sample_count + old_entries,
3705 (GDestroyNotify) qtdemux_gst_structure_free);
3707 /* We preserve old entries because we parse the next moof in advance
3708 * of consuming all samples from the previous moof, and otherwise
3709 * we'd discard the corresponding crypto info for the samples
3710 * from the previous fragment. */
3712 GST_DEBUG_OBJECT (qtdemux, "Preserving %d old crypto info entries",
3714 for (i = old_crypto_info->len - old_entries; i < old_crypto_info->len; i++) {
3715 g_ptr_array_add (ss_info->crypto_info, g_ptr_array_index (old_crypto_info,
3717 g_ptr_array_index (old_crypto_info, i) = NULL;
3721 if (old_crypto_info) {
3722 /* Everything now belongs to the new array */
3723 g_ptr_array_free (old_crypto_info, TRUE);
3726 for (i = 0; i < sample_count; ++i) {
3727 GstStructure *properties;
3728 guint16 n_subsamples = 0;
3733 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3734 if (properties == NULL) {
3735 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3738 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3739 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3740 gst_structure_free (properties);
3743 if (!gst_byte_reader_dup_data (br, iv_size, &data)) {
3744 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3745 gst_structure_free (properties);
3748 buf = gst_buffer_new_wrapped (data, iv_size);
3749 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3750 gst_buffer_unref (buf);
3751 size = info_sizes[i];
3752 if (size > iv_size) {
3753 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3754 || !(n_subsamples > 0)) {
3755 gst_structure_free (properties);
3756 GST_ERROR_OBJECT (qtdemux,
3757 "failed to get subsample count for sample %u", i);
3760 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3761 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3762 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3764 gst_structure_free (properties);
3767 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3769 gst_structure_free (properties);
3772 gst_structure_set (properties,
3773 "subsample_count", G_TYPE_UINT, n_subsamples,
3774 "subsamples", GST_TYPE_BUFFER, buf, NULL);
3775 gst_buffer_unref (buf);
3777 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3779 g_ptr_array_add (ss_info->crypto_info, properties);
3784 /* Converts a UUID in raw byte form to a string representation, as defined in
3785 * RFC 4122. The caller takes ownership of the returned string and is
3786 * responsible for freeing it after use. */
3788 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3790 const guint8 *uuid = (const guint8 *) uuid_bytes;
3792 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3793 "%02x%02x-%02x%02x%02x%02x%02x%02x",
3794 uuid[0], uuid[1], uuid[2], uuid[3],
3795 uuid[4], uuid[5], uuid[6], uuid[7],
3796 uuid[8], uuid[9], uuid[10], uuid[11],
3797 uuid[12], uuid[13], uuid[14], uuid[15]);
3800 /* Parses a Protection System Specific Header box (pssh), as defined in the
3801 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3802 * information needed by a specific content protection system in order to
3803 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3806 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
3808 gchar *sysid_string;
3809 guint32 pssh_size = QT_UINT32 (node->data);
3810 GstBuffer *pssh = NULL;
3811 GstEvent *event = NULL;
3812 guint32 parent_box_type;
3815 if (G_UNLIKELY (pssh_size < 32U)) {
3816 GST_ERROR_OBJECT (qtdemux, "invalid box size");
3821 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
3823 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
3825 pssh = gst_buffer_new_wrapped (g_memdup (node->data, pssh_size), pssh_size);
3826 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
3827 gst_buffer_get_size (pssh));
3829 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
3831 /* Push an event containing the pssh box onto the queues of all streams. */
3832 event = gst_event_new_protection (sysid_string, pssh,
3833 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
3834 for (i = 0; i < qtdemux->n_streams; ++i) {
3835 g_queue_push_tail (&qtdemux->streams[i]->protection_scheme_event_queue,
3836 gst_event_ref (event));
3838 g_free (sysid_string);
3839 gst_event_unref (event);
3840 gst_buffer_unref (pssh);
3845 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
3846 guint64 moof_offset, QtDemuxStream * stream)
3848 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
3850 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
3851 GNode *saiz_node, *saio_node, *pssh_node;
3852 GstByteReader saiz_data, saio_data;
3853 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
3854 gint64 base_offset, running_offset;
3857 /* NOTE @stream ignored */
3859 moof_node = g_node_new ((guint8 *) buffer);
3860 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
3861 qtdemux_node_dump (qtdemux, moof_node);
3863 /* Get fragment number from mfhd and check it's valid */
3865 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
3866 if (mfhd_node == NULL)
3868 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
3870 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
3872 /* unknown base_offset to start with */
3873 base_offset = running_offset = -1;
3874 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
3876 guint64 decode_time = 0;
3878 /* Fragment Header node */
3880 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
3884 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
3885 &ds_size, &ds_flags, &base_offset))
3888 /* The following code assumes at most a single set of sample auxiliary
3889 * data in the fragment (consisting of a saiz box and a corresponding saio
3890 * box); in theory, however, there could be multiple sets of sample
3891 * auxiliary data in a fragment. */
3893 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
3896 guint32 info_type = 0;
3898 guint32 info_type_parameter = 0;
3900 g_free (qtdemux->cenc_aux_info_sizes);
3902 qtdemux->cenc_aux_info_sizes =
3903 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
3904 &qtdemux->cenc_aux_sample_count);
3905 if (qtdemux->cenc_aux_info_sizes == NULL) {
3906 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
3910 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
3913 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
3914 g_free (qtdemux->cenc_aux_info_sizes);
3915 qtdemux->cenc_aux_info_sizes = NULL;
3919 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
3920 &info_type, &info_type_parameter, &offset))) {
3921 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
3922 g_free (qtdemux->cenc_aux_info_sizes);
3923 qtdemux->cenc_aux_info_sizes = NULL;
3926 if (base_offset > -1 && base_offset > qtdemux->moof_offset)
3927 offset += (guint64) (base_offset - qtdemux->moof_offset);
3928 if (info_type == FOURCC_cenc && info_type_parameter == 0U) {
3930 if (offset > length) {
3931 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
3932 qtdemux->cenc_aux_info_offset = offset;
3934 gst_byte_reader_init (&br, buffer + offset, length - offset);
3935 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
3936 qtdemux->cenc_aux_info_sizes,
3937 qtdemux->cenc_aux_sample_count)) {
3938 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
3939 g_free (qtdemux->cenc_aux_info_sizes);
3940 qtdemux->cenc_aux_info_sizes = NULL;
3948 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
3951 /* We'll use decode_time to interpolate timestamps
3952 * in case the input timestamps are missing */
3953 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
3955 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
3956 " (%" GST_TIME_FORMAT ")", decode_time,
3957 GST_TIME_ARGS (stream ? QTSTREAMTIME_TO_GSTTIME (stream,
3958 decode_time) : GST_CLOCK_TIME_NONE));
3960 /* Discard the fragment buffer timestamp info to avoid using it.
3961 * Rely on tfdt instead as it is more accurate than the timestamp
3962 * that is fetched from a manifest/playlist and is usually
3964 qtdemux->fragment_start = -1;
3967 if (G_UNLIKELY (!stream)) {
3968 /* we lost track of offset, we'll need to regain it,
3969 * but can delay complaining until later or avoid doing so altogether */
3973 if (G_UNLIKELY (base_offset < -1))
3976 if (qtdemux->upstream_format_is_time)
3977 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
3979 /* initialise moof sample data */
3980 stream->n_samples_moof = 0;
3981 stream->duration_last_moof = stream->duration_moof;
3982 stream->duration_moof = 0;
3984 /* Track Run node */
3986 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
3989 qtdemux_parse_trun (qtdemux, &trun_data, stream,
3990 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
3991 &running_offset, decode_time, (tfdt_node != NULL));
3992 /* iterate all siblings */
3993 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
3997 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
3999 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
4000 guint32 box_length = QT_UINT32 (uuid_buffer);
4002 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
4005 /* if no new base_offset provided for next traf,
4006 * base is end of current traf */
4007 base_offset = running_offset;
4008 running_offset = -1;
4010 if (stream->n_samples_moof && stream->duration_moof)
4011 stream->new_caps = TRUE;
4014 /* iterate all siblings */
4015 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
4018 /* parse any protection system info */
4019 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
4021 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
4022 qtdemux_parse_pssh (qtdemux, pssh_node);
4023 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
4026 g_node_destroy (moof_node);
4031 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
4036 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
4041 GST_DEBUG_OBJECT (qtdemux, "lost offset");
4046 g_node_destroy (moof_node);
4047 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4048 (_("This file is corrupt and cannot be played.")), (NULL));
4054 /* might be used if some day we actually use mfra & co
4055 * for random access to fragments,
4056 * but that will require quite some modifications and much less relying
4057 * on a sample array */
4061 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
4063 QtDemuxStream *stream;
4064 guint32 ver_flags, track_id, len, num_entries, i;
4065 guint value_size, traf_size, trun_size, sample_size;
4066 guint64 time = 0, moof_offset = 0;
4068 GstBuffer *buf = NULL;
4073 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
4075 if (!gst_byte_reader_skip (&tfra, 8))
4078 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
4081 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
4082 || !gst_byte_reader_get_uint32_be (&tfra, &len)
4083 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
4086 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
4088 stream = qtdemux_find_stream (qtdemux, track_id);
4090 goto unknown_trackid;
4092 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
4093 sample_size = (len & 3) + 1;
4094 trun_size = ((len & 12) >> 2) + 1;
4095 traf_size = ((len & 48) >> 4) + 1;
4097 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
4098 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
4100 if (num_entries == 0)
4103 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
4104 value_size + value_size + traf_size + trun_size + sample_size))
4107 g_free (stream->ra_entries);
4108 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
4109 stream->n_ra_entries = num_entries;
4111 for (i = 0; i < num_entries; i++) {
4112 qt_atom_parser_get_offset (&tfra, value_size, &time);
4113 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
4114 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
4115 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
4116 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
4118 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
4120 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
4121 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
4123 stream->ra_entries[i].ts = time;
4124 stream->ra_entries[i].moof_offset = moof_offset;
4126 /* don't want to go through the entire file and read all moofs at startup */
4128 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
4129 if (ret != GST_FLOW_OK)
4131 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
4132 moof_offset, stream);
4133 gst_buffer_unref (buf);
4137 check_update_duration (qtdemux, time);
4144 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
4149 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
4154 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4160 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
4162 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
4163 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
4164 GstBuffer *mfro = NULL, *mfra = NULL;
4166 gboolean ret = FALSE;
4167 GNode *mfra_node, *tfra_node;
4168 guint64 mfra_offset = 0;
4169 guint32 fourcc, mfra_size;
4172 /* query upstream size in bytes */
4173 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4174 goto size_query_failed;
4176 /* mfro box should be at the very end of the file */
4177 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4178 if (flow != GST_FLOW_OK)
4181 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4183 fourcc = QT_FOURCC (mfro_map.data + 4);
4184 if (fourcc != FOURCC_mfro)
4187 GST_INFO_OBJECT (qtdemux, "Found mfro box");
4188 if (mfro_map.size < 16)
4189 goto invalid_mfro_size;
4191 mfra_size = QT_UINT32 (mfro_map.data + 12);
4192 if (mfra_size >= len)
4193 goto invalid_mfra_size;
4195 mfra_offset = len - mfra_size;
4197 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4198 mfra_offset, mfra_size);
4200 /* now get and parse mfra box */
4201 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4202 if (flow != GST_FLOW_OK)
4205 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4207 mfra_node = g_node_new ((guint8 *) mfra_map.data);
4208 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4210 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4213 qtdemux_parse_tfra (qtdemux, tfra_node);
4214 /* iterate all siblings */
4215 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4217 g_node_destroy (mfra_node);
4219 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4225 if (mfro_map.memory != NULL)
4226 gst_buffer_unmap (mfro, &mfro_map);
4227 gst_buffer_unref (mfro);
4230 if (mfra_map.memory != NULL)
4231 gst_buffer_unmap (mfra, &mfra_map);
4232 gst_buffer_unref (mfra);
4239 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4244 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4249 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4254 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4260 add_offset (guint64 offset, guint64 advance)
4262 /* Avoid 64-bit overflow by clamping */
4263 if (offset > G_MAXUINT64 - advance)
4265 return offset + advance;
4268 static GstFlowReturn
4269 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4273 GstBuffer *buf = NULL;
4274 GstFlowReturn ret = GST_FLOW_OK;
4275 guint64 cur_offset = qtdemux->offset;
4278 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4279 if (G_UNLIKELY (ret != GST_FLOW_OK))
4281 gst_buffer_map (buf, &map, GST_MAP_READ);
4282 if (G_LIKELY (map.size >= 8))
4283 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4284 gst_buffer_unmap (buf, &map);
4285 gst_buffer_unref (buf);
4287 /* maybe we already got most we needed, so only consider this eof */
4288 if (G_UNLIKELY (length == 0)) {
4289 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4290 (_("Invalid atom size.")),
4291 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4292 GST_FOURCC_ARGS (fourcc)));
4299 /* record for later parsing when needed */
4300 if (!qtdemux->moof_offset) {
4301 qtdemux->moof_offset = qtdemux->offset;
4303 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4306 qtdemux->offset += length; /* skip moof and keep going */
4308 if (qtdemux->got_moov) {
4309 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4321 GST_LOG_OBJECT (qtdemux,
4322 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4323 GST_FOURCC_ARGS (fourcc), cur_offset);
4324 qtdemux->offset = add_offset (qtdemux->offset, length);
4329 GstBuffer *moov = NULL;
4331 if (qtdemux->got_moov) {
4332 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4333 qtdemux->offset = add_offset (qtdemux->offset, length);
4337 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4338 if (ret != GST_FLOW_OK)
4340 gst_buffer_map (moov, &map, GST_MAP_READ);
4342 if (length != map.size) {
4343 /* Some files have a 'moov' atom at the end of the file which contains
4344 * a terminal 'free' atom where the body of the atom is missing.
4345 * Check for, and permit, this special case.
4347 if (map.size >= 8) {
4348 guint8 *final_data = map.data + (map.size - 8);
4349 guint32 final_length = QT_UINT32 (final_data);
4350 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4352 if (final_fourcc == FOURCC_free
4353 && map.size + final_length - 8 == length) {
4354 /* Ok, we've found that special case. Allocate a new buffer with
4355 * that free atom actually present. */
4356 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4357 gst_buffer_fill (newmoov, 0, map.data, map.size);
4358 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4359 gst_buffer_unmap (moov, &map);
4360 gst_buffer_unref (moov);
4362 gst_buffer_map (moov, &map, GST_MAP_READ);
4367 if (length != map.size) {
4368 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4369 (_("This file is incomplete and cannot be played.")),
4370 ("We got less than expected (received %" G_GSIZE_FORMAT
4371 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4372 (guint) length, cur_offset));
4373 gst_buffer_unmap (moov, &map);
4374 gst_buffer_unref (moov);
4375 ret = GST_FLOW_ERROR;
4378 qtdemux->offset += length;
4380 qtdemux_parse_moov (qtdemux, map.data, length);
4381 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4383 qtdemux_parse_tree (qtdemux);
4384 if (qtdemux->moov_node_compressed) {
4385 g_node_destroy (qtdemux->moov_node_compressed);
4386 g_free (qtdemux->moov_node->data);
4388 qtdemux->moov_node_compressed = NULL;
4389 g_node_destroy (qtdemux->moov_node);
4390 qtdemux->moov_node = NULL;
4391 gst_buffer_unmap (moov, &map);
4392 gst_buffer_unref (moov);
4393 qtdemux->got_moov = TRUE;
4399 GstBuffer *ftyp = NULL;
4401 /* extract major brand; might come in handy for ISO vs QT issues */
4402 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4403 if (ret != GST_FLOW_OK)
4405 qtdemux->offset += length;
4406 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4407 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4408 gst_buffer_unmap (ftyp, &map);
4409 gst_buffer_unref (ftyp);
4414 GstBuffer *uuid = NULL;
4416 /* uuid are extension atoms */
4417 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4418 if (ret != GST_FLOW_OK)
4420 qtdemux->offset += length;
4421 gst_buffer_map (uuid, &map, GST_MAP_READ);
4422 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4423 gst_buffer_unmap (uuid, &map);
4424 gst_buffer_unref (uuid);
4429 GstBuffer *sidx = NULL;
4430 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4431 if (ret != GST_FLOW_OK)
4433 qtdemux->offset += length;
4434 gst_buffer_map (sidx, &map, GST_MAP_READ);
4435 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4436 gst_buffer_unmap (sidx, &map);
4437 gst_buffer_unref (sidx);
4442 GstBuffer *unknown = NULL;
4444 GST_LOG_OBJECT (qtdemux,
4445 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4446 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4448 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4449 if (ret != GST_FLOW_OK)
4451 gst_buffer_map (unknown, &map, GST_MAP_READ);
4452 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4453 gst_buffer_unmap (unknown, &map);
4454 gst_buffer_unref (unknown);
4455 qtdemux->offset += length;
4461 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4462 /* digested all data, show what we have */
4463 qtdemux_prepare_streams (qtdemux);
4464 ret = qtdemux_expose_streams (qtdemux);
4466 qtdemux->state = QTDEMUX_STATE_MOVIE;
4467 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4474 /* Seeks to the previous keyframe of the indexed stream and
4475 * aligns other streams with respect to the keyframe timestamp
4476 * of indexed stream. Only called in case of Reverse Playback
4478 static GstFlowReturn
4479 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4482 guint32 seg_idx = 0, k_index = 0;
4483 guint32 ref_seg_idx, ref_k_index;
4484 GstClockTime k_pos = 0, last_stop = 0;
4485 QtDemuxSegment *seg = NULL;
4486 QtDemuxStream *ref_str = NULL;
4487 guint64 seg_media_start_mov; /* segment media start time in mov format */
4490 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4491 * and finally align all the other streams on that timestamp with their
4492 * respective keyframes */
4493 for (n = 0; n < qtdemux->n_streams; n++) {
4494 QtDemuxStream *str = qtdemux->streams[n];
4496 /* No candidate yet, take the first stream */
4502 /* So that stream has a segment, we prefer video streams */
4503 if (str->subtype == FOURCC_vide) {
4509 if (G_UNLIKELY (!ref_str)) {
4510 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4514 if (G_UNLIKELY (!ref_str->from_sample)) {
4515 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4519 /* So that stream has been playing from from_sample to to_sample. We will
4520 * get the timestamp of the previous sample and search for a keyframe before
4521 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4522 if (ref_str->subtype == FOURCC_vide) {
4523 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4524 ref_str->from_sample - 1, FALSE);
4526 if (ref_str->from_sample >= 10)
4527 k_index = ref_str->from_sample - 10;
4533 ref_str->samples[k_index].timestamp +
4534 ref_str->samples[k_index].pts_offset;
4536 /* get current segment for that stream */
4537 seg = &ref_str->segments[ref_str->segment_index];
4538 /* Use segment start in original timescale for comparisons */
4539 seg_media_start_mov = seg->trak_media_start;
4541 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4542 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT "\n",
4543 k_index, target_ts, seg_media_start_mov,
4544 GST_TIME_ARGS (seg->media_start));
4546 /* Crawl back through segments to find the one containing this I frame */
4547 while (target_ts < seg_media_start_mov) {
4548 GST_DEBUG_OBJECT (qtdemux,
4549 "keyframe position (sample %u) is out of segment %u " " target %"
4550 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4551 ref_str->segment_index, target_ts, seg_media_start_mov);
4553 if (G_UNLIKELY (!ref_str->segment_index)) {
4554 /* Reached first segment, let's consider it's EOS */
4557 ref_str->segment_index--;
4558 seg = &ref_str->segments[ref_str->segment_index];
4559 /* Use segment start in original timescale for comparisons */
4560 seg_media_start_mov = seg->trak_media_start;
4562 /* Calculate time position of the keyframe and where we should stop */
4564 QTSTREAMTIME_TO_GSTTIME (ref_str,
4565 target_ts - seg->trak_media_start) + seg->time;
4567 QTSTREAMTIME_TO_GSTTIME (ref_str,
4568 ref_str->samples[ref_str->from_sample].timestamp -
4569 seg->trak_media_start) + seg->time;
4571 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4572 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4573 k_index, GST_TIME_ARGS (k_pos));
4575 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4576 qtdemux->segment.position = last_stop;
4577 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4578 GST_TIME_ARGS (last_stop));
4580 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4581 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4585 ref_seg_idx = ref_str->segment_index;
4586 ref_k_index = k_index;
4588 /* Align them all on this */
4589 for (n = 0; n < qtdemux->n_streams; n++) {
4591 GstClockTime seg_time = 0;
4592 QtDemuxStream *str = qtdemux->streams[n];
4594 /* aligning reference stream again might lead to backing up to yet another
4595 * keyframe (due to timestamp rounding issues),
4596 * potentially putting more load on downstream; so let's try to avoid */
4597 if (str == ref_str) {
4598 seg_idx = ref_seg_idx;
4599 seg = &str->segments[seg_idx];
4600 k_index = ref_k_index;
4601 GST_DEBUG_OBJECT (qtdemux, "reference stream %d segment %d, "
4602 "sample at index %d", n, ref_str->segment_index, k_index);
4604 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4605 GST_DEBUG_OBJECT (qtdemux,
4606 "stream %d align segment %d for keyframe pos %" GST_TIME_FORMAT, n,
4607 seg_idx, GST_TIME_ARGS (k_pos));
4609 /* get segment and time in the segment */
4610 seg = &str->segments[seg_idx];
4611 seg_time = k_pos - seg->time;
4613 /* get the media time in the segment.
4614 * No adjustment for empty "filler" segments */
4615 if (seg->media_start != GST_CLOCK_TIME_NONE)
4616 seg_time += seg->media_start;
4618 /* get the index of the sample with media time */
4619 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4620 GST_DEBUG_OBJECT (qtdemux,
4621 "stream %d sample for %" GST_TIME_FORMAT " at %u", n,
4622 GST_TIME_ARGS (seg_time), index);
4624 /* find previous keyframe */
4625 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
4628 /* Remember until where we want to go */
4629 str->to_sample = str->from_sample - 1;
4630 /* Define our time position */
4632 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4633 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4634 if (seg->media_start != GST_CLOCK_TIME_NONE)
4635 str->time_position -= seg->media_start;
4637 /* Now seek back in time */
4638 gst_qtdemux_move_stream (qtdemux, str, k_index);
4639 GST_DEBUG_OBJECT (qtdemux, "stream %d keyframe at %u, time position %"
4640 GST_TIME_FORMAT " playing from sample %u to %u", n, k_index,
4641 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4647 return GST_FLOW_EOS;
4651 * Gets the current qt segment start, stop and position for the
4652 * given time offset. This is used in update_segment()
4655 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
4656 QtDemuxStream * stream, GstClockTime offset,
4657 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
4659 GstClockTime seg_time;
4660 GstClockTime start, stop, time;
4661 QtDemuxSegment *segment;
4663 segment = &stream->segments[stream->segment_index];
4665 /* get time in this segment */
4666 seg_time = (offset - segment->time) * segment->rate;
4668 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4669 GST_TIME_ARGS (seg_time));
4671 if (G_UNLIKELY (seg_time > segment->duration)) {
4672 GST_LOG_OBJECT (stream->pad,
4673 "seg_time > segment->duration %" GST_TIME_FORMAT,
4674 GST_TIME_ARGS (segment->duration));
4675 seg_time = segment->duration;
4678 /* qtdemux->segment.stop is in outside-time-realm, whereas
4679 * segment->media_stop is in track-time-realm.
4681 * In order to compare the two, we need to bring segment.stop
4682 * into the track-time-realm
4684 * FIXME - does this comment still hold? Don't see any conversion here */
4686 stop = qtdemux->segment.stop;
4687 if (stop == GST_CLOCK_TIME_NONE)
4688 stop = qtdemux->segment.duration;
4689 if (stop == GST_CLOCK_TIME_NONE)
4690 stop = segment->media_stop;
4693 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4695 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4696 start = segment->time + seg_time;
4698 stop = start - seg_time + segment->duration;
4699 } else if (qtdemux->segment.rate >= 0) {
4700 start = MIN (segment->media_start + seg_time, stop);
4703 if (segment->media_start >= qtdemux->segment.start) {
4704 time = segment->time;
4706 time = segment->time + (qtdemux->segment.start - segment->media_start);
4709 start = MAX (segment->media_start, qtdemux->segment.start);
4710 stop = MIN (segment->media_start + seg_time, stop);
4719 * Updates the qt segment used for the stream and pushes a new segment event
4720 * downstream on this stream's pad.
4723 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4724 gint seg_idx, GstClockTime offset, GstClockTime * _start,
4725 GstClockTime * _stop)
4727 QtDemuxSegment *segment;
4728 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
4732 /* update the current segment */
4733 stream->segment_index = seg_idx;
4735 /* get the segment */
4736 segment = &stream->segments[seg_idx];
4738 if (G_UNLIKELY (offset < segment->time)) {
4739 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4740 GST_TIME_ARGS (segment->time));
4744 /* segment lies beyond total indicated duration */
4745 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4746 segment->time > qtdemux->segment.duration)) {
4747 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4748 " < segment->time %" GST_TIME_FORMAT,
4749 GST_TIME_ARGS (qtdemux->segment.duration),
4750 GST_TIME_ARGS (segment->time));
4754 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
4755 &start, &stop, &time);
4757 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
4758 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
4759 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
4761 /* combine global rate with that of the segment */
4762 rate = segment->rate * qtdemux->segment.rate;
4764 /* Copy flags from main segment */
4765 stream->segment.flags = qtdemux->segment.flags;
4767 /* update the segment values used for clipping */
4768 stream->segment.offset = qtdemux->segment.offset;
4769 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
4770 stream->segment.applied_rate = qtdemux->segment.applied_rate;
4771 stream->segment.rate = rate;
4772 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
4773 stream->cslg_shift);
4774 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
4775 stream->cslg_shift);
4776 stream->segment.time = time;
4777 stream->segment.position = stream->segment.start;
4779 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
4782 /* now prepare and send the segment */
4784 event = gst_event_new_segment (&stream->segment);
4785 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
4786 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
4788 gst_pad_push_event (stream->pad, event);
4789 /* assume we can send more data now */
4790 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
4791 /* clear to send tags on this pad now */
4792 gst_qtdemux_push_tags (qtdemux, stream);
4803 /* activate the given segment number @seg_idx of @stream at time @offset.
4804 * @offset is an absolute global position over all the segments.
4806 * This will push out a NEWSEGMENT event with the right values and
4807 * position the stream index to the first decodable sample before
4811 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4812 guint32 seg_idx, GstClockTime offset)
4814 QtDemuxSegment *segment;
4815 guint32 index, kf_index;
4816 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
4818 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
4819 seg_idx, GST_TIME_ARGS (offset));
4821 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
4825 segment = &stream->segments[stream->segment_index];
4827 /* in the fragmented case, we pick a fragment that starts before our
4828 * desired position and rely on downstream to wait for a keyframe
4829 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
4830 * tfra entries tells us which trun/sample the key unit is in, but we don't
4831 * make use of this additional information at the moment) */
4832 if (qtdemux->fragmented && !qtdemux->fragmented_seek_pending) {
4833 stream->to_sample = G_MAXUINT32;
4836 /* well, it will be taken care of below */
4837 qtdemux->fragmented_seek_pending = FALSE;
4838 /* FIXME ideally the do_fragmented_seek can be done right here,
4839 * rather than at loop level
4840 * (which might even allow handling edit lists in a fragmented file) */
4843 /* We don't need to look for a sample in push-based */
4844 if (!qtdemux->pullbased)
4847 /* and move to the keyframe before the indicated media time of the
4849 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
4850 if (qtdemux->segment.rate >= 0) {
4851 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
4852 stream->to_sample = G_MAXUINT32;
4853 GST_DEBUG_OBJECT (stream->pad,
4854 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4855 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
4856 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4858 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
4859 stream->to_sample = index;
4860 GST_DEBUG_OBJECT (stream->pad,
4861 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4862 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
4863 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4866 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
4867 "this is an empty segment");
4871 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
4872 * encountered an error and printed a message so we return appropriately */
4876 /* we're at the right spot */
4877 if (index == stream->sample_index) {
4878 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
4882 /* find keyframe of the target index */
4883 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
4886 /* indent does stupid stuff with stream->samples[].timestamp */
4888 /* if we move forwards, we don't have to go back to the previous
4889 * keyframe since we already sent that. We can also just jump to
4890 * the keyframe right before the target index if there is one. */
4891 if (index > stream->sample_index) {
4892 /* moving forwards check if we move past a keyframe */
4893 if (kf_index > stream->sample_index) {
4894 GST_DEBUG_OBJECT (stream->pad,
4895 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4896 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4897 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4898 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4900 GST_DEBUG_OBJECT (stream->pad,
4901 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
4902 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
4903 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
4906 GST_DEBUG_OBJECT (stream->pad,
4907 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4908 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4909 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4910 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4918 /* prepare to get the current sample of @stream, getting essential values.
4920 * This function will also prepare and send the segment when needed.
4922 * Return FALSE if the stream is EOS.
4927 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
4928 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
4929 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
4930 gboolean * keyframe)
4932 QtDemuxSample *sample;
4933 GstClockTime time_position;
4936 g_return_val_if_fail (stream != NULL, FALSE);
4938 time_position = stream->time_position;
4939 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
4942 seg_idx = stream->segment_index;
4943 if (G_UNLIKELY (seg_idx == -1)) {
4944 /* find segment corresponding to time_position if we are looking
4946 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
4949 /* different segment, activate it, sample_index will be set. */
4950 if (G_UNLIKELY (stream->segment_index != seg_idx))
4951 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
4953 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->segments[stream->
4955 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
4957 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
4958 " prepare empty sample");
4961 *pts = *dts = time_position;
4962 *duration = seg->duration - (time_position - seg->time);
4969 if (stream->sample_index == -1)
4970 stream->sample_index = 0;
4972 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
4973 stream->sample_index, stream->n_samples);
4975 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
4976 if (!qtdemux->fragmented)
4979 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
4983 GST_OBJECT_LOCK (qtdemux);
4984 flow = qtdemux_add_fragmented_samples (qtdemux);
4985 GST_OBJECT_UNLOCK (qtdemux);
4987 if (flow != GST_FLOW_OK)
4990 while (stream->sample_index >= stream->n_samples);
4993 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4994 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4995 stream->sample_index);
4999 /* now get the info for the sample we're at */
5000 sample = &stream->samples[stream->sample_index];
5002 *dts = QTSAMPLE_DTS (stream, sample);
5003 *pts = QTSAMPLE_PTS (stream, sample);
5004 *offset = sample->offset;
5005 *size = sample->size;
5006 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
5007 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5014 stream->time_position = GST_CLOCK_TIME_NONE;
5019 /* move to the next sample in @stream.
5021 * Moves to the next segment when needed.
5024 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
5026 QtDemuxSample *sample;
5027 QtDemuxSegment *segment;
5029 /* get current segment */
5030 segment = &stream->segments[stream->segment_index];
5032 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5033 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
5037 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
5038 /* Mark the stream as EOS */
5039 GST_DEBUG_OBJECT (qtdemux,
5040 "reached max allowed sample %u, mark EOS", stream->to_sample);
5041 stream->time_position = GST_CLOCK_TIME_NONE;
5045 /* move to next sample */
5046 stream->sample_index++;
5047 stream->offset_in_sample = 0;
5049 /* reached the last sample, we need the next segment */
5050 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
5053 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5054 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5055 stream->sample_index);
5059 /* get next sample */
5060 sample = &stream->samples[stream->sample_index];
5062 /* see if we are past the segment */
5063 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
5066 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
5067 /* inside the segment, update time_position, looks very familiar to
5068 * GStreamer segments, doesn't it? */
5069 stream->time_position =
5070 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
5072 /* not yet in segment, time does not yet increment. This means
5073 * that we are still prerolling keyframes to the decoder so it can
5074 * decode the first sample of the segment. */
5075 stream->time_position = segment->time;
5079 /* move to the next segment */
5082 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
5084 if (stream->segment_index == stream->n_segments - 1) {
5085 /* are we at the end of the last segment, we're EOS */
5086 stream->time_position = GST_CLOCK_TIME_NONE;
5088 /* else we're only at the end of the current segment */
5089 stream->time_position = segment->stop_time;
5091 /* make sure we select a new segment */
5093 /* accumulate previous segments */
5094 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
5095 stream->accumulated_base +=
5096 (stream->segment.stop -
5097 stream->segment.start) / ABS (stream->segment.rate);
5099 stream->segment_index = -1;
5104 gst_qtdemux_sync_streams (GstQTDemux * demux)
5108 if (demux->n_streams <= 1)
5111 for (i = 0; i < demux->n_streams; i++) {
5112 QtDemuxStream *stream;
5113 GstClockTime end_time;
5115 stream = demux->streams[i];
5120 /* TODO advance time on subtitle streams here, if any some day */
5122 /* some clips/trailers may have unbalanced streams at the end,
5123 * so send EOS on shorter stream to prevent stalling others */
5125 /* do not mess with EOS if SEGMENT seeking */
5126 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5129 if (demux->pullbased) {
5130 /* loop mode is sample time based */
5131 if (!STREAM_IS_EOS (stream))
5134 /* push mode is byte position based */
5135 if (stream->n_samples &&
5136 stream->samples[stream->n_samples - 1].offset >= demux->offset)
5140 if (stream->sent_eos)
5143 /* only act if some gap */
5144 end_time = stream->segments[stream->n_segments - 1].stop_time;
5145 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5146 ", stream end: %" GST_TIME_FORMAT,
5147 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5148 if (GST_CLOCK_TIME_IS_VALID (end_time)
5149 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5152 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5153 GST_PAD_NAME (stream->pad));
5154 stream->sent_eos = TRUE;
5155 event = gst_event_new_eos ();
5156 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
5157 gst_event_set_seqnum (event, demux->segment_seqnum);
5158 gst_pad_push_event (stream->pad, event);
5163 /* EOS and NOT_LINKED need to be combined. This means that we return:
5165 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
5166 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
5168 static GstFlowReturn
5169 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
5172 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
5175 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5178 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5180 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5184 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5185 * completely clipped
5187 * Should be used only with raw buffers */
5189 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5192 guint64 start, stop, cstart, cstop, diff;
5193 GstClockTime pts, duration;
5195 gint num_rate, denom_rate;
5200 osize = size = gst_buffer_get_size (buf);
5203 /* depending on the type, setup the clip parameters */
5204 if (stream->subtype == FOURCC_soun) {
5205 frame_size = CUR_STREAM (stream)->bytes_per_frame;
5206 num_rate = GST_SECOND;
5207 denom_rate = (gint) CUR_STREAM (stream)->rate;
5209 } else if (stream->subtype == FOURCC_vide) {
5211 num_rate = CUR_STREAM (stream)->fps_n;
5212 denom_rate = CUR_STREAM (stream)->fps_d;
5217 if (frame_size <= 0)
5218 goto bad_frame_size;
5220 /* we can only clip if we have a valid pts */
5221 pts = GST_BUFFER_PTS (buf);
5222 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5225 duration = GST_BUFFER_DURATION (buf);
5227 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5229 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5233 stop = start + duration;
5235 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5236 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5239 /* see if some clipping happened */
5240 diff = cstart - start;
5246 /* bring clipped time to samples and to bytes */
5247 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5250 GST_DEBUG_OBJECT (qtdemux,
5251 "clipping start to %" GST_TIME_FORMAT " %"
5252 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5258 diff = stop - cstop;
5263 /* bring clipped time to samples and then to bytes */
5264 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5266 GST_DEBUG_OBJECT (qtdemux,
5267 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5268 " bytes", GST_TIME_ARGS (cstop), diff);
5273 if (offset != 0 || size != osize)
5274 gst_buffer_resize (buf, offset, size);
5276 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5277 GST_BUFFER_PTS (buf) = pts;
5278 GST_BUFFER_DURATION (buf) = duration;
5282 /* dropped buffer */
5285 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5290 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5295 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5300 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5301 gst_buffer_unref (buf);
5307 gst_qtdemux_align_buffer (GstQTDemux * demux,
5308 GstBuffer * buffer, gsize alignment)
5312 gst_buffer_map (buffer, &map, GST_MAP_READ);
5314 if (map.size < sizeof (guintptr)) {
5315 gst_buffer_unmap (buffer, &map);
5319 if (((guintptr) map.data) & (alignment - 1)) {
5320 GstBuffer *new_buffer;
5321 GstAllocationParams params = { 0, alignment - 1, 0, 0, };
5323 new_buffer = gst_buffer_new_allocate (NULL,
5324 gst_buffer_get_size (buffer), ¶ms);
5326 /* Copy data "by hand", so ensure alignment is kept: */
5327 gst_buffer_fill (new_buffer, 0, map.data, map.size);
5329 gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
5330 GST_DEBUG_OBJECT (demux,
5331 "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
5334 gst_buffer_unmap (buffer, &map);
5335 gst_buffer_unref (buffer);
5340 gst_buffer_unmap (buffer, &map);
5344 /* the input buffer metadata must be writable,
5345 * but time/duration etc not yet set and need not be preserved */
5347 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5354 /* not many cases for now */
5355 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_mp4s)) {
5356 /* send a one time dvd clut event */
5357 if (stream->pending_event && stream->pad)
5358 gst_pad_push_event (stream->pad, stream->pending_event);
5359 stream->pending_event = NULL;
5362 if (G_UNLIKELY (stream->subtype != FOURCC_text
5363 && stream->subtype != FOURCC_sbtl &&
5364 stream->subtype != FOURCC_subp)) {
5368 gst_buffer_map (buf, &map, GST_MAP_READ);
5370 /* empty buffer is sent to terminate previous subtitle */
5371 if (map.size <= 2) {
5372 gst_buffer_unmap (buf, &map);
5373 gst_buffer_unref (buf);
5376 if (stream->subtype == FOURCC_subp) {
5377 /* That's all the processing needed for subpictures */
5378 gst_buffer_unmap (buf, &map);
5382 nsize = GST_READ_UINT16_BE (map.data);
5383 nsize = MIN (nsize, map.size - 2);
5385 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5388 /* takes care of UTF-8 validation or UTF-16 recognition,
5389 * no other encoding expected */
5390 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5391 gst_buffer_unmap (buf, &map);
5393 gst_buffer_unref (buf);
5394 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5396 /* this should not really happen unless the subtitle is corrupted */
5397 gst_buffer_unref (buf);
5401 /* FIXME ? convert optional subsequent style info to markup */
5406 /* Sets a buffer's attributes properly and pushes it downstream.
5407 * Also checks for additional actions and custom processing that may
5408 * need to be done first.
5410 static GstFlowReturn
5411 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
5412 QtDemuxStream * stream, GstBuffer * buf,
5413 GstClockTime dts, GstClockTime pts, GstClockTime duration,
5414 gboolean keyframe, GstClockTime position, guint64 byte_position)
5416 GstFlowReturn ret = GST_FLOW_OK;
5418 /* offset the timestamps according to the edit list */
5420 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) {
5424 gst_buffer_map (buf, &map, GST_MAP_READ);
5425 url = g_strndup ((gchar *) map.data, map.size);
5426 gst_buffer_unmap (buf, &map);
5427 if (url != NULL && strlen (url) != 0) {
5428 /* we have RTSP redirect now */
5429 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5430 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
5431 gst_structure_new ("redirect",
5432 "new-location", G_TYPE_STRING, url, NULL)));
5433 qtdemux->posted_redirect = TRUE;
5435 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
5441 /* position reporting */
5442 if (qtdemux->segment.rate >= 0) {
5443 qtdemux->segment.position = position;
5444 gst_qtdemux_sync_streams (qtdemux);
5447 if (G_UNLIKELY (!stream->pad)) {
5448 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
5449 gst_buffer_unref (buf);
5453 /* send out pending buffers */
5454 while (stream->buffers) {
5455 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
5457 if (G_UNLIKELY (stream->discont)) {
5458 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5459 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
5460 stream->discont = FALSE;
5462 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5465 if (stream->alignment > 1)
5466 buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
5467 gst_pad_push (stream->pad, buffer);
5469 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
5472 /* we're going to modify the metadata */
5473 buf = gst_buffer_make_writable (buf);
5475 if (G_UNLIKELY (stream->need_process))
5476 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
5482 GST_BUFFER_DTS (buf) = dts;
5483 GST_BUFFER_PTS (buf) = pts;
5484 GST_BUFFER_DURATION (buf) = duration;
5485 GST_BUFFER_OFFSET (buf) = -1;
5486 GST_BUFFER_OFFSET_END (buf) = -1;
5488 if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette))
5489 gst_buffer_append_memory (buf,
5490 gst_memory_ref (CUR_STREAM (stream)->rgb8_palette));
5492 if (G_UNLIKELY (CUR_STREAM (stream)->padding)) {
5493 gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1);
5496 if (G_UNLIKELY (qtdemux->element_index)) {
5497 GstClockTime stream_time;
5500 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
5502 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
5503 GST_LOG_OBJECT (qtdemux,
5504 "adding association %" GST_TIME_FORMAT "-> %"
5505 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
5506 gst_index_add_association (qtdemux->element_index,
5508 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
5509 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
5510 GST_FORMAT_BYTES, byte_position, NULL);
5515 if (stream->need_clip)
5516 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5518 if (G_UNLIKELY (buf == NULL))
5521 if (G_UNLIKELY (stream->discont)) {
5522 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5523 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5524 stream->discont = FALSE;
5526 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5530 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
5531 stream->on_keyframe = FALSE;
5533 stream->on_keyframe = TRUE;
5537 GST_LOG_OBJECT (qtdemux,
5538 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5539 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
5540 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
5541 GST_PAD_NAME (stream->pad));
5543 if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) {
5544 GstStructure *crypto_info;
5545 QtDemuxCencSampleSetInfo *info =
5546 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5550 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5551 gst_pad_push_event (stream->pad, event);
5554 if (info->crypto_info == NULL) {
5555 GST_DEBUG_OBJECT (qtdemux, "cenc metadata hasn't been parsed yet");
5556 gst_buffer_unref (buf);
5560 /* The end of the crypto_info array matches our n_samples position,
5561 * so count backward from there */
5562 index = stream->sample_index - stream->n_samples + info->crypto_info->len;
5563 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5564 /* steal structure from array */
5565 crypto_info = g_ptr_array_index (info->crypto_info, index);
5566 g_ptr_array_index (info->crypto_info, index) = NULL;
5567 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
5568 info->crypto_info->len);
5569 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5570 GST_ERROR_OBJECT (qtdemux, "failed to attach cenc metadata to buffer");
5572 GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
5573 index, stream->sample_index);
5577 if (stream->alignment > 1)
5578 buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
5580 ret = gst_pad_push (stream->pad, buf);
5582 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
5583 /* mark position in stream, we'll need this to know when to send GAP event */
5584 stream->segment.position = pts + duration;
5591 static const QtDemuxRandomAccessEntry *
5592 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5593 GstClockTime pos, gboolean after)
5595 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
5596 guint n_entries = stream->n_ra_entries;
5599 /* we assume the table is sorted */
5600 for (i = 0; i < n_entries; ++i) {
5601 if (entries[i].ts > pos)
5605 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
5606 * probably okay to assume that the index lists the very first fragment */
5613 return &entries[i - 1];
5617 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
5619 const QtDemuxRandomAccessEntry *best_entry = NULL;
5622 GST_OBJECT_LOCK (qtdemux);
5624 g_assert (qtdemux->n_streams > 0);
5626 /* first see if we can determine where to go to using mfra,
5627 * before we start clearing things */
5628 for (i = 0; i < qtdemux->n_streams; i++) {
5629 const QtDemuxRandomAccessEntry *entry;
5630 QtDemuxStream *stream;
5631 gboolean is_audio_or_video;
5633 stream = qtdemux->streams[i];
5635 if (stream->ra_entries == NULL)
5638 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
5639 is_audio_or_video = TRUE;
5641 is_audio_or_video = FALSE;
5644 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
5645 stream->time_position, !is_audio_or_video);
5647 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
5648 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
5650 stream->pending_seek = entry;
5652 /* decide position to jump to just based on audio/video tracks, not subs */
5653 if (!is_audio_or_video)
5656 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
5660 /* no luck, will handle seek otherwise */
5661 if (best_entry == NULL) {
5662 GST_OBJECT_UNLOCK (qtdemux);
5666 /* ok, now we can prepare for processing as of located moof */
5667 for (i = 0; i < qtdemux->n_streams; i++) {
5668 QtDemuxStream *stream;
5670 stream = qtdemux->streams[i];
5672 g_free (stream->samples);
5673 stream->samples = NULL;
5674 stream->n_samples = 0;
5675 stream->stbl_index = -1; /* no samples have yet been parsed */
5676 stream->sample_index = -1;
5678 if (stream->protection_scheme_info) {
5679 /* Clear out any old cenc crypto info entries as we'll move to a new moof */
5680 if (stream->protection_scheme_type == FOURCC_cenc) {
5681 QtDemuxCencSampleSetInfo *info =
5682 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5683 if (info->crypto_info) {
5684 g_ptr_array_free (info->crypto_info, TRUE);
5685 info->crypto_info = NULL;
5691 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
5692 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
5693 GST_TIME_ARGS (qtdemux->streams[0]->time_position),
5694 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
5696 qtdemux->moof_offset = best_entry->moof_offset;
5698 qtdemux_add_fragmented_samples (qtdemux);
5700 GST_OBJECT_UNLOCK (qtdemux);
5704 static GstFlowReturn
5705 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
5707 GstFlowReturn ret = GST_FLOW_OK;
5708 GstBuffer *buf = NULL;
5709 QtDemuxStream *stream;
5710 GstClockTime min_time;
5712 GstClockTime dts = GST_CLOCK_TIME_NONE;
5713 GstClockTime pts = GST_CLOCK_TIME_NONE;
5714 GstClockTime duration = 0;
5715 gboolean keyframe = FALSE;
5716 guint sample_size = 0;
5722 gst_qtdemux_push_pending_newsegment (qtdemux);
5724 if (qtdemux->fragmented_seek_pending) {
5725 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
5726 if (gst_qtdemux_do_fragmented_seek (qtdemux)) {
5727 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
5728 qtdemux->fragmented_seek_pending = FALSE;
5730 GST_INFO_OBJECT (qtdemux, "fragmented seek still pending");
5734 /* Figure out the next stream sample to output, min_time is expressed in
5735 * global time and runs over the edit list segments. */
5736 min_time = G_MAXUINT64;
5738 for (i = 0; i < qtdemux->n_streams; i++) {
5739 GstClockTime position;
5741 stream = qtdemux->streams[i];
5742 position = stream->time_position;
5744 /* position of -1 is EOS */
5745 if (position != GST_CLOCK_TIME_NONE && position < min_time) {
5746 min_time = position;
5751 if (G_UNLIKELY (index == -1)) {
5752 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
5756 /* check for segment end */
5757 if (G_UNLIKELY (qtdemux->segment.stop != -1
5758 && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
5759 || (qtdemux->segment.rate < 0
5760 && qtdemux->segment.start > min_time))
5761 && qtdemux->streams[index]->on_keyframe)) {
5762 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
5763 qtdemux->streams[index]->time_position = GST_CLOCK_TIME_NONE;
5767 /* gap events for subtitle streams */
5768 for (i = 0; i < qtdemux->n_streams; i++) {
5769 stream = qtdemux->streams[i];
5770 if (stream->pad && (stream->subtype == FOURCC_subp
5771 || stream->subtype == FOURCC_text
5772 || stream->subtype == FOURCC_sbtl)) {
5773 /* send one second gap events until the stream catches up */
5774 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
5775 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
5776 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
5777 stream->segment.position + GST_SECOND < min_time) {
5779 gst_event_new_gap (stream->segment.position, GST_SECOND);
5780 gst_pad_push_event (stream->pad, gap);
5781 stream->segment.position += GST_SECOND;
5786 stream = qtdemux->streams[index];
5787 /* fetch info for the current sample of this stream */
5788 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
5789 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
5792 gst_qtdemux_stream_check_and_change_stsd_index (qtdemux, stream);
5793 if (stream->new_caps) {
5794 gst_qtdemux_configure_stream (qtdemux, stream);
5795 qtdemux_do_allocation (qtdemux, stream);
5798 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
5799 if (G_UNLIKELY (qtdemux->
5800 segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
5801 if (stream->subtype == FOURCC_vide && !keyframe) {
5802 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on stream %d", index);
5807 GST_DEBUG_OBJECT (qtdemux,
5808 "pushing from stream %d, empty %d offset %" G_GUINT64_FORMAT
5809 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
5810 ", duration %" GST_TIME_FORMAT, index, empty, offset, sample_size,
5811 GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
5813 if (G_UNLIKELY (empty)) {
5814 /* empty segment, push a gap and move to the next one */
5815 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
5816 stream->segment.position = pts + duration;
5820 /* hmm, empty sample, skip and move to next sample */
5821 if (G_UNLIKELY (sample_size <= 0))
5824 /* last pushed sample was out of boundary, goto next sample */
5825 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
5828 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
5831 GST_DEBUG_OBJECT (qtdemux,
5832 "size %d larger than stream max_buffer_size %d, trimming",
5833 sample_size, stream->max_buffer_size);
5835 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
5838 if (qtdemux->cenc_aux_info_offset > 0) {
5841 GstBuffer *aux_info = NULL;
5843 /* pull the data stored before the sample */
5845 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
5846 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
5847 if (G_UNLIKELY (ret != GST_FLOW_OK))
5849 gst_buffer_map (aux_info, &map, GST_MAP_READ);
5850 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
5851 gst_byte_reader_init (&br, map.data + 8, map.size);
5852 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
5853 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
5854 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
5855 gst_buffer_unmap (aux_info, &map);
5856 gst_buffer_unref (aux_info);
5857 ret = GST_FLOW_ERROR;
5860 gst_buffer_unmap (aux_info, &map);
5861 gst_buffer_unref (aux_info);
5864 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
5867 if (stream->use_allocator) {
5868 /* if we have a per-stream allocator, use it */
5869 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
5872 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
5874 if (G_UNLIKELY (ret != GST_FLOW_OK))
5877 if (size != sample_size) {
5878 pts += gst_util_uint64_scale_int (GST_SECOND,
5879 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
5882 gst_util_uint64_scale_int (GST_SECOND,
5883 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
5886 gst_util_uint64_scale_int (GST_SECOND,
5887 size / CUR_STREAM (stream)->bytes_per_frame, stream->timescale);
5890 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
5891 dts, pts, duration, keyframe, min_time, offset);
5893 if (size != sample_size) {
5894 QtDemuxSample *sample = &stream->samples[stream->sample_index];
5895 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
5897 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
5899 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame);
5900 if (time_position >= segment->media_start) {
5901 /* inside the segment, update time_position, looks very familiar to
5902 * GStreamer segments, doesn't it? */
5903 stream->time_position = (time_position - segment->media_start) +
5906 /* not yet in segment, time does not yet increment. This means
5907 * that we are still prerolling keyframes to the decoder so it can
5908 * decode the first sample of the segment. */
5909 stream->time_position = segment->time;
5914 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
5915 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
5916 * we have no more data for the pad to push */
5917 if (ret == GST_FLOW_EOS)
5920 stream->offset_in_sample += size;
5921 if (stream->offset_in_sample >= sample_size) {
5922 gst_qtdemux_advance_sample (qtdemux, stream);
5927 gst_qtdemux_advance_sample (qtdemux, stream);
5935 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
5941 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
5942 /* EOS will be raised if all are EOS */
5949 gst_qtdemux_loop (GstPad * pad)
5951 GstQTDemux *qtdemux;
5955 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
5957 cur_offset = qtdemux->offset;
5958 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
5959 cur_offset, qt_demux_state_string (qtdemux->state));
5961 switch (qtdemux->state) {
5962 case QTDEMUX_STATE_INITIAL:
5963 case QTDEMUX_STATE_HEADER:
5964 ret = gst_qtdemux_loop_state_header (qtdemux);
5966 case QTDEMUX_STATE_MOVIE:
5967 ret = gst_qtdemux_loop_state_movie (qtdemux);
5968 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
5969 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
5977 /* if something went wrong, pause */
5978 if (ret != GST_FLOW_OK)
5982 gst_object_unref (qtdemux);
5988 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
5989 (NULL), ("streaming stopped, invalid state"));
5990 gst_pad_pause_task (pad);
5991 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5996 const gchar *reason = gst_flow_get_name (ret);
5998 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
6000 gst_pad_pause_task (pad);
6002 /* fatal errors need special actions */
6004 if (ret == GST_FLOW_EOS) {
6005 if (qtdemux->n_streams == 0) {
6006 /* we have no streams, post an error */
6007 gst_qtdemux_post_no_playable_stream_error (qtdemux);
6009 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
6012 if ((stop = qtdemux->segment.stop) == -1)
6013 stop = qtdemux->segment.duration;
6015 if (qtdemux->segment.rate >= 0) {
6016 GstMessage *message;
6019 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
6020 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6021 GST_FORMAT_TIME, stop);
6022 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
6023 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6024 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6025 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6027 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6028 gst_qtdemux_push_event (qtdemux, event);
6030 GstMessage *message;
6033 /* For Reverse Playback */
6034 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
6035 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6036 GST_FORMAT_TIME, qtdemux->segment.start);
6037 event = gst_event_new_segment_done (GST_FORMAT_TIME,
6038 qtdemux->segment.start);
6039 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6040 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6041 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6043 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6044 gst_qtdemux_push_event (qtdemux, event);
6049 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
6050 event = gst_event_new_eos ();
6051 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
6052 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6053 gst_qtdemux_push_event (qtdemux, event);
6055 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
6056 GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
6057 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6066 * Returns if there are samples to be played.
6069 has_next_entry (GstQTDemux * demux)
6071 QtDemuxStream *stream;
6074 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
6076 for (i = 0; i < demux->n_streams; i++) {
6077 stream = demux->streams[i];
6079 if (stream->sample_index == -1) {
6080 stream->sample_index = 0;
6081 stream->offset_in_sample = 0;
6084 if (stream->sample_index >= stream->n_samples) {
6085 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
6088 GST_DEBUG_OBJECT (demux, "Found a sample");
6092 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
6099 * Returns the size of the first entry at the current offset.
6100 * If -1, there are none (which means EOS or empty file).
6103 next_entry_size (GstQTDemux * demux)
6105 QtDemuxStream *stream;
6108 guint64 smalloffs = (guint64) - 1;
6109 QtDemuxSample *sample;
6111 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
6114 for (i = 0; i < demux->n_streams; i++) {
6115 stream = demux->streams[i];
6117 if (stream->sample_index == -1) {
6118 stream->sample_index = 0;
6119 stream->offset_in_sample = 0;
6122 if (stream->sample_index >= stream->n_samples) {
6123 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
6127 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
6128 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
6129 stream->sample_index);
6133 sample = &stream->samples[stream->sample_index];
6135 GST_LOG_OBJECT (demux,
6136 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
6137 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
6138 sample->offset, sample->size);
6140 if (((smalloffs == -1)
6141 || (sample->offset < smalloffs)) && (sample->size)) {
6143 smalloffs = sample->offset;
6147 GST_LOG_OBJECT (demux,
6148 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
6149 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
6154 stream = demux->streams[smallidx];
6155 sample = &stream->samples[stream->sample_index];
6157 if (sample->offset >= demux->offset) {
6158 demux->todrop = sample->offset - demux->offset;
6159 return sample->size + demux->todrop;
6162 GST_DEBUG_OBJECT (demux,
6163 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
6168 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
6170 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
6172 gst_element_post_message (GST_ELEMENT_CAST (demux),
6173 gst_message_new_element (GST_OBJECT_CAST (demux),
6174 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
6178 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
6183 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
6186 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
6187 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
6188 GST_SEEK_TYPE_NONE, -1);
6190 /* store seqnum to drop flush events, they don't need to reach downstream */
6191 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
6192 res = gst_pad_push_event (demux->sinkpad, event);
6193 demux->offset_seek_seqnum = GST_SEQNUM_INVALID;
6198 /* check for seekable upstream, above and beyond a mere query */
6200 gst_qtdemux_check_seekability (GstQTDemux * demux)
6203 gboolean seekable = FALSE;
6204 gint64 start = -1, stop = -1;
6206 if (demux->upstream_size)
6209 if (demux->upstream_format_is_time)
6212 query = gst_query_new_seeking (GST_FORMAT_BYTES);
6213 if (!gst_pad_peer_query (demux->sinkpad, query)) {
6214 GST_DEBUG_OBJECT (demux, "seeking query failed");
6218 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
6220 /* try harder to query upstream size if we didn't get it the first time */
6221 if (seekable && stop == -1) {
6222 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
6223 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
6226 /* if upstream doesn't know the size, it's likely that it's not seekable in
6227 * practice even if it technically may be seekable */
6228 if (seekable && (start != 0 || stop <= start)) {
6229 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
6234 gst_query_unref (query);
6236 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
6237 G_GUINT64_FORMAT ")", seekable, start, stop);
6238 demux->upstream_seekable = seekable;
6239 demux->upstream_size = seekable ? stop : -1;
6243 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
6245 g_return_if_fail (bytes <= demux->todrop);
6247 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
6248 gst_adapter_flush (demux->adapter, bytes);
6249 demux->neededbytes -= bytes;
6250 demux->offset += bytes;
6251 demux->todrop -= bytes;
6255 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
6257 if (G_UNLIKELY (demux->pending_newsegment)) {
6260 gst_qtdemux_push_pending_newsegment (demux);
6261 /* clear to send tags on all streams */
6262 for (i = 0; i < demux->n_streams; i++) {
6263 QtDemuxStream *stream;
6264 stream = demux->streams[i];
6265 gst_qtdemux_push_tags (demux, stream);
6266 if (CUR_STREAM (stream)->sparse) {
6267 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
6268 gst_pad_push_event (stream->pad,
6269 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
6276 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
6277 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
6279 GstClockTime ts, dur;
6284 stream->segments[segment_index].duration - (pos -
6285 stream->segments[segment_index].time);
6286 gap = gst_event_new_gap (ts, dur);
6287 stream->time_position += dur;
6289 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
6290 "segment: %" GST_PTR_FORMAT, gap);
6291 gst_pad_push_event (stream->pad, gap);
6295 gst_qtdemux_stream_send_initial_gap_segments (GstQTDemux * demux,
6296 QtDemuxStream * stream)
6300 /* Push any initial gap segments before proceeding to the
6302 for (i = 0; i < stream->n_segments; i++) {
6303 gst_qtdemux_activate_segment (demux, stream, i, stream->time_position);
6305 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
6306 gst_qtdemux_send_gap_for_segment (demux, stream, i,
6307 stream->time_position);
6309 /* Only support empty segment at the beginning followed by
6310 * one non-empty segment, this was checked when parsing the
6311 * edts atom, arriving here is unexpected */
6312 g_assert (i + 1 == stream->n_segments);
6318 static GstFlowReturn
6319 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
6323 demux = GST_QTDEMUX (parent);
6325 GST_DEBUG_OBJECT (demux,
6326 "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
6327 " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
6328 G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
6329 GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
6330 gst_buffer_get_size (inbuf), demux->offset);
6332 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
6333 gboolean is_gap_input = FALSE;
6336 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
6338 for (i = 0; i < demux->n_streams; i++) {
6339 demux->streams[i]->discont = TRUE;
6342 /* Check if we can land back on our feet in the case where upstream is
6343 * handling the seeking/pushing of samples with gaps in between (like
6344 * in the case of trick-mode DASH for example) */
6345 if (demux->upstream_format_is_time
6346 && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
6348 for (i = 0; i < demux->n_streams; i++) {
6350 GST_LOG_OBJECT (demux,
6351 "Stream #%d , checking if offset %" G_GUINT64_FORMAT
6352 " is a sample start", i, GST_BUFFER_OFFSET (inbuf));
6354 gst_qtdemux_find_index_for_given_media_offset_linear (demux,
6355 demux->streams[i], GST_BUFFER_OFFSET (inbuf));
6357 QtDemuxSample *sample = &demux->streams[i]->samples[res];
6358 GST_LOG_OBJECT (demux,
6359 "Checking if sample %d from stream %d is valid (offset:%"
6360 G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res, i,
6361 sample->offset, sample->size);
6362 if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
6363 GST_LOG_OBJECT (demux,
6364 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
6366 is_gap_input = TRUE;
6367 /* We can go back to standard playback mode */
6368 demux->state = QTDEMUX_STATE_MOVIE;
6369 /* Remember which sample this stream is at */
6370 demux->streams[i]->sample_index = res;
6371 /* Finally update all push-based values to the expected values */
6372 demux->neededbytes = demux->streams[i]->samples[res].size;
6373 demux->offset = GST_BUFFER_OFFSET (inbuf);
6375 demux->mdatsize - demux->offset + demux->mdatoffset;
6380 if (!is_gap_input) {
6381 GST_DEBUG_OBJECT (demux, "Resetting, actual DISCONT");
6382 /* Reset state if it's a real discont */
6383 demux->neededbytes = 16;
6384 demux->state = QTDEMUX_STATE_INITIAL;
6385 demux->offset = GST_BUFFER_OFFSET (inbuf);
6386 gst_adapter_clear (demux->adapter);
6389 /* Reverse fragmented playback, need to flush all we have before
6390 * consuming a new fragment.
6391 * The samples array have the timestamps calculated by accumulating the
6392 * durations but this won't work for reverse playback of fragments as
6393 * the timestamps of a subsequent fragment should be smaller than the
6394 * previously received one. */
6395 if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
6396 gst_qtdemux_process_adapter (demux, TRUE);
6397 for (i = 0; i < demux->n_streams; i++)
6398 gst_qtdemux_stream_flush_samples_data (demux, demux->streams[i]);
6402 gst_adapter_push (demux->adapter, inbuf);
6404 GST_DEBUG_OBJECT (demux,
6405 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
6406 demux->neededbytes, gst_adapter_available (demux->adapter));
6408 return gst_qtdemux_process_adapter (demux, FALSE);
6411 static GstFlowReturn
6412 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
6414 GstFlowReturn ret = GST_FLOW_OK;
6416 /* we never really mean to buffer that much */
6417 if (demux->neededbytes == -1) {
6421 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
6422 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
6424 #ifndef GST_DISABLE_GST_DEBUG
6426 guint64 discont_offset, distance_from_discont;
6428 discont_offset = gst_adapter_offset_at_discont (demux->adapter);
6429 distance_from_discont =
6430 gst_adapter_distance_from_discont (demux->adapter);
6432 GST_DEBUG_OBJECT (demux,
6433 "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
6434 " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
6435 " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
6436 demux->offset, discont_offset, distance_from_discont);
6440 switch (demux->state) {
6441 case QTDEMUX_STATE_INITIAL:{
6446 gst_qtdemux_check_seekability (demux);
6448 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6450 /* get fourcc/length, set neededbytes */
6451 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
6453 gst_adapter_unmap (demux->adapter);
6455 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
6456 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
6458 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6459 (_("This file is invalid and cannot be played.")),
6460 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
6461 GST_FOURCC_ARGS (fourcc)));
6462 ret = GST_FLOW_ERROR;
6465 if (fourcc == FOURCC_mdat) {
6466 gint next_entry = next_entry_size (demux);
6467 if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
6468 /* we have the headers, start playback */
6469 demux->state = QTDEMUX_STATE_MOVIE;
6470 demux->neededbytes = next_entry;
6471 demux->mdatleft = size;
6472 demux->mdatsize = demux->mdatleft;
6474 /* no headers yet, try to get them */
6477 guint64 old, target;
6480 old = demux->offset;
6481 target = old + size;
6483 /* try to jump over the atom with a seek */
6484 /* only bother if it seems worth doing so,
6485 * and avoids possible upstream/server problems */
6486 if (demux->upstream_seekable &&
6487 demux->upstream_size > 4 * (1 << 20)) {
6488 res = qtdemux_seek_offset (demux, target);
6490 GST_DEBUG_OBJECT (demux, "skipping seek");
6495 GST_DEBUG_OBJECT (demux, "seek success");
6496 /* remember the offset fo the first mdat so we can seek back to it
6497 * after we have the headers */
6498 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
6499 demux->first_mdat = old;
6500 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
6503 /* seek worked, continue reading */
6504 demux->offset = target;
6505 demux->neededbytes = 16;
6506 demux->state = QTDEMUX_STATE_INITIAL;
6508 /* seek failed, need to buffer */
6509 demux->offset = old;
6510 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
6511 /* there may be multiple mdat (or alike) buffers */
6513 if (demux->mdatbuffer)
6514 bs = gst_buffer_get_size (demux->mdatbuffer);
6517 if (size + bs > 10 * (1 << 20))
6519 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
6520 demux->neededbytes = size;
6521 if (!demux->mdatbuffer)
6522 demux->mdatoffset = demux->offset;
6525 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
6526 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6527 (_("This file is invalid and cannot be played.")),
6528 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
6529 GST_FOURCC_ARGS (fourcc), size));
6530 ret = GST_FLOW_ERROR;
6533 /* this means we already started buffering and still no moov header,
6534 * let's continue buffering everything till we get moov */
6535 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
6536 || fourcc == FOURCC_moof))
6538 demux->neededbytes = size;
6539 demux->state = QTDEMUX_STATE_HEADER;
6543 case QTDEMUX_STATE_HEADER:{
6547 GST_DEBUG_OBJECT (demux, "In header");
6549 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6551 /* parse the header */
6552 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
6554 if (fourcc == FOURCC_moov) {
6557 /* in usual fragmented setup we could try to scan for more
6558 * and end up at the the moov (after mdat) again */
6559 if (demux->got_moov && demux->n_streams > 0 &&
6561 || demux->last_moov_offset == demux->offset)) {
6562 GST_DEBUG_OBJECT (demux,
6563 "Skipping moov atom as we have (this) one already");
6565 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
6567 if (demux->got_moov && demux->fragmented) {
6568 GST_DEBUG_OBJECT (demux,
6569 "Got a second moov, clean up data from old one");
6570 if (demux->moov_node_compressed) {
6571 g_node_destroy (demux->moov_node_compressed);
6572 if (demux->moov_node)
6573 g_free (demux->moov_node->data);
6575 demux->moov_node_compressed = NULL;
6576 if (demux->moov_node)
6577 g_node_destroy (demux->moov_node);
6578 demux->moov_node = NULL;
6580 /* prepare newsegment to send when streaming actually starts */
6581 if (!demux->pending_newsegment) {
6582 demux->pending_newsegment =
6583 gst_event_new_segment (&demux->segment);
6584 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
6585 gst_event_set_seqnum (demux->pending_newsegment,
6586 demux->segment_seqnum);
6590 demux->last_moov_offset = demux->offset;
6592 qtdemux_parse_moov (demux, data, demux->neededbytes);
6593 qtdemux_node_dump (demux, demux->moov_node);
6594 qtdemux_parse_tree (demux);
6595 qtdemux_prepare_streams (demux);
6596 if (!demux->got_moov)
6597 qtdemux_expose_streams (demux);
6600 for (n = 0; n < demux->n_streams; n++) {
6601 QtDemuxStream *stream = demux->streams[n];
6603 gst_qtdemux_configure_stream (demux, stream);
6607 demux->got_moov = TRUE;
6608 gst_qtdemux_check_send_pending_segment (demux);
6610 /* fragmented streams headers shouldn't contain edts atoms */
6611 if (!demux->fragmented) {
6612 for (n = 0; n < demux->n_streams; n++) {
6613 gst_qtdemux_stream_send_initial_gap_segments (demux,
6618 if (demux->moov_node_compressed) {
6619 g_node_destroy (demux->moov_node_compressed);
6620 g_free (demux->moov_node->data);
6622 demux->moov_node_compressed = NULL;
6623 g_node_destroy (demux->moov_node);
6624 demux->moov_node = NULL;
6625 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
6627 } else if (fourcc == FOURCC_moof) {
6628 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
6630 GstClockTime prev_pts;
6631 guint64 prev_offset;
6632 guint64 adapter_discont_offset, adapter_discont_dist;
6634 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
6637 * The timestamp of the moof buffer is relevant as some scenarios
6638 * won't have the initial timestamp in the atoms. Whenever a new
6639 * buffer has started, we get that buffer's PTS and use it as a base
6640 * timestamp for the trun entries.
6642 * To keep track of the current buffer timestamp and starting point
6643 * we use gst_adapter_prev_pts that gives us the PTS and the distance
6644 * from the beggining of the buffer, with the distance and demux->offset
6645 * we know if it is still the same buffer or not.
6647 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
6648 prev_offset = demux->offset - dist;
6649 if (demux->fragment_start_offset == -1
6650 || prev_offset > demux->fragment_start_offset) {
6651 demux->fragment_start_offset = prev_offset;
6652 demux->fragment_start = prev_pts;
6653 GST_DEBUG_OBJECT (demux,
6654 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
6655 GST_TIME_FORMAT, demux->fragment_start_offset,
6656 GST_TIME_ARGS (demux->fragment_start));
6659 /* We can't use prev_offset() here because this would require
6660 * upstream to set consistent and correct offsets on all buffers
6661 * since the discont. Nothing ever did that in the past and we
6662 * would break backwards compatibility here then.
6663 * Instead take the offset we had at the last discont and count
6664 * the bytes from there. This works with old code as there would
6665 * be no discont between moov and moof, and also works with
6666 * adaptivedemux which correctly sets offset and will set the
6667 * DISCONT flag accordingly when needed.
6669 * We also only do this for upstream TIME segments as otherwise
6670 * there are potential backwards compatibility problems with
6671 * seeking in PUSH mode and upstream providing inconsistent
6673 adapter_discont_offset =
6674 gst_adapter_offset_at_discont (demux->adapter);
6675 adapter_discont_dist =
6676 gst_adapter_distance_from_discont (demux->adapter);
6678 GST_DEBUG_OBJECT (demux,
6679 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
6680 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
6681 demux->offset, adapter_discont_offset, adapter_discont_dist);
6683 if (demux->upstream_format_is_time) {
6684 demux->moof_offset = adapter_discont_offset;
6685 if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
6686 demux->moof_offset += adapter_discont_dist;
6687 if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
6688 demux->moof_offset = demux->offset;
6690 demux->moof_offset = demux->offset;
6693 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
6694 demux->moof_offset, NULL)) {
6695 gst_adapter_unmap (demux->adapter);
6696 ret = GST_FLOW_ERROR;
6699 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
6700 if (demux->mss_mode && !demux->exposed) {
6701 if (!demux->pending_newsegment) {
6702 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
6703 demux->pending_newsegment =
6704 gst_event_new_segment (&demux->segment);
6705 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
6706 gst_event_set_seqnum (demux->pending_newsegment,
6707 demux->segment_seqnum);
6709 qtdemux_expose_streams (demux);
6712 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
6714 } else if (fourcc == FOURCC_ftyp) {
6715 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
6716 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
6717 } else if (fourcc == FOURCC_uuid) {
6718 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
6719 qtdemux_parse_uuid (demux, data, demux->neededbytes);
6720 } else if (fourcc == FOURCC_sidx) {
6721 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
6722 qtdemux_parse_sidx (demux, data, demux->neededbytes);
6726 /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
6730 /* [free] and [skip] are padding atoms */
6731 GST_DEBUG_OBJECT (demux,
6732 "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
6733 GST_FOURCC_ARGS (fourcc));
6736 GST_WARNING_OBJECT (demux,
6737 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
6738 GST_FOURCC_ARGS (fourcc));
6739 /* Let's jump that one and go back to initial state */
6743 gst_adapter_unmap (demux->adapter);
6746 if (demux->mdatbuffer && demux->n_streams) {
6747 gsize remaining_data_size = 0;
6749 /* the mdat was before the header */
6750 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
6751 demux->n_streams, demux->mdatbuffer);
6752 /* restore our adapter/offset view of things with upstream;
6753 * put preceding buffered data ahead of current moov data.
6754 * This should also handle evil mdat, moov, mdat cases and alike */
6755 gst_adapter_flush (demux->adapter, demux->neededbytes);
6757 /* Store any remaining data after the mdat for later usage */
6758 remaining_data_size = gst_adapter_available (demux->adapter);
6759 if (remaining_data_size > 0) {
6760 g_assert (demux->restoredata_buffer == NULL);
6761 demux->restoredata_buffer =
6762 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
6763 demux->restoredata_offset = demux->offset + demux->neededbytes;
6764 GST_DEBUG_OBJECT (demux,
6765 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
6766 G_GUINT64_FORMAT, remaining_data_size,
6767 demux->restoredata_offset);
6770 gst_adapter_push (demux->adapter, demux->mdatbuffer);
6771 demux->mdatbuffer = NULL;
6772 demux->offset = demux->mdatoffset;
6773 demux->neededbytes = next_entry_size (demux);
6774 demux->state = QTDEMUX_STATE_MOVIE;
6775 demux->mdatleft = gst_adapter_available (demux->adapter);
6776 demux->mdatsize = demux->mdatleft;
6778 GST_DEBUG_OBJECT (demux, "Carrying on normally");
6779 gst_adapter_flush (demux->adapter, demux->neededbytes);
6781 /* only go back to the mdat if there are samples to play */
6782 if (demux->got_moov && demux->first_mdat != -1
6783 && has_next_entry (demux)) {
6786 /* we need to seek back */
6787 res = qtdemux_seek_offset (demux, demux->first_mdat);
6789 demux->offset = demux->first_mdat;
6791 GST_DEBUG_OBJECT (demux, "Seek back failed");
6794 demux->offset += demux->neededbytes;
6796 demux->neededbytes = 16;
6797 demux->state = QTDEMUX_STATE_INITIAL;
6802 case QTDEMUX_STATE_BUFFER_MDAT:{
6806 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
6808 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6809 gst_buffer_extract (buf, 0, fourcc, 4);
6810 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
6811 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
6812 if (demux->mdatbuffer)
6813 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
6815 demux->mdatbuffer = buf;
6816 demux->offset += demux->neededbytes;
6817 demux->neededbytes = 16;
6818 demux->state = QTDEMUX_STATE_INITIAL;
6819 gst_qtdemux_post_progress (demux, 1, 1);
6823 case QTDEMUX_STATE_MOVIE:{
6824 QtDemuxStream *stream = NULL;
6825 QtDemuxSample *sample;
6827 GstClockTime dts, pts, duration;
6830 GST_DEBUG_OBJECT (demux,
6831 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
6833 if (demux->fragmented) {
6834 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
6836 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
6837 /* if needed data starts within this atom,
6838 * then it should not exceed this atom */
6839 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
6840 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6841 (_("This file is invalid and cannot be played.")),
6842 ("sample data crosses atom boundary"));
6843 ret = GST_FLOW_ERROR;
6846 demux->mdatleft -= demux->neededbytes;
6848 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
6849 /* so we are dropping more than left in this atom */
6850 gst_qtdemux_drop_data (demux, demux->mdatleft);
6851 demux->mdatleft = 0;
6853 /* need to resume atom parsing so we do not miss any other pieces */
6854 demux->state = QTDEMUX_STATE_INITIAL;
6855 demux->neededbytes = 16;
6857 /* check if there was any stored post mdat data from previous buffers */
6858 if (demux->restoredata_buffer) {
6859 g_assert (gst_adapter_available (demux->adapter) == 0);
6861 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
6862 demux->restoredata_buffer = NULL;
6863 demux->offset = demux->restoredata_offset;
6870 if (demux->todrop) {
6871 if (demux->cenc_aux_info_offset > 0) {
6875 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
6876 data = gst_adapter_map (demux->adapter, demux->todrop);
6877 gst_byte_reader_init (&br, data + 8, demux->todrop);
6878 if (!qtdemux_parse_cenc_aux_info (demux, demux->streams[0], &br,
6879 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
6880 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
6881 ret = GST_FLOW_ERROR;
6882 gst_adapter_unmap (demux->adapter);
6883 g_free (demux->cenc_aux_info_sizes);
6884 demux->cenc_aux_info_sizes = NULL;
6887 demux->cenc_aux_info_offset = 0;
6888 g_free (demux->cenc_aux_info_sizes);
6889 demux->cenc_aux_info_sizes = NULL;
6890 gst_adapter_unmap (demux->adapter);
6892 gst_qtdemux_drop_data (demux, demux->todrop);
6896 /* initial newsegment sent here after having added pads,
6897 * possible others in sink_event */
6898 gst_qtdemux_check_send_pending_segment (demux);
6900 /* Figure out which stream this packet belongs to */
6901 for (i = 0; i < demux->n_streams; i++) {
6902 stream = demux->streams[i];
6903 if (stream->sample_index >= stream->n_samples)
6905 GST_LOG_OBJECT (demux,
6906 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
6907 " / size:%d)", i, stream->sample_index,
6908 stream->samples[stream->sample_index].offset,
6909 stream->samples[stream->sample_index].size);
6911 if (stream->samples[stream->sample_index].offset == demux->offset)
6915 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
6916 goto unknown_stream;
6918 gst_qtdemux_stream_check_and_change_stsd_index (demux, stream);
6920 if (stream->new_caps) {
6921 gst_qtdemux_configure_stream (demux, stream);
6924 /* Put data in a buffer, set timestamps, caps, ... */
6925 sample = &stream->samples[stream->sample_index];
6927 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
6928 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
6929 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
6931 dts = QTSAMPLE_DTS (stream, sample);
6932 pts = QTSAMPLE_PTS (stream, sample);
6933 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
6934 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
6936 /* check for segment end */
6937 if (G_UNLIKELY (demux->segment.stop != -1
6938 && demux->segment.stop <= pts && stream->on_keyframe)) {
6939 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
6940 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
6942 /* skip this data, stream is EOS */
6943 gst_adapter_flush (demux->adapter, demux->neededbytes);
6944 demux->offset += demux->neededbytes;
6946 /* check if all streams are eos */
6948 for (i = 0; i < demux->n_streams; i++) {
6949 if (!STREAM_IS_EOS (demux->streams[i])) {
6958 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6960 /* FIXME: should either be an assert or a plain check */
6961 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
6963 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
6964 dts, pts, duration, keyframe, dts, demux->offset);
6968 ret = gst_qtdemux_combine_flows (demux, stream, ret);
6970 /* skip this data, stream is EOS */
6971 gst_adapter_flush (demux->adapter, demux->neededbytes);
6974 stream->sample_index++;
6975 stream->offset_in_sample = 0;
6977 /* update current offset and figure out size of next buffer */
6978 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
6979 demux->offset, demux->neededbytes);
6980 demux->offset += demux->neededbytes;
6981 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
6985 if (ret == GST_FLOW_EOS) {
6986 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
6987 demux->neededbytes = -1;
6991 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
6992 if (demux->fragmented) {
6993 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
6994 /* there may be more to follow, only finish this atom */
6995 demux->todrop = demux->mdatleft;
6996 demux->neededbytes = demux->todrop;
7001 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
7002 goto non_ok_unlinked_flow;
7011 /* when buffering movie data, at least show user something is happening */
7012 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
7013 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
7014 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
7015 demux->neededbytes);
7022 non_ok_unlinked_flow:
7024 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
7025 gst_flow_get_name (ret));
7030 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
7031 ret = GST_FLOW_ERROR;
7036 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
7042 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7043 (NULL), ("qtdemuxer invalid state %d", demux->state));
7044 ret = GST_FLOW_ERROR;
7049 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7050 (NULL), ("no 'moov' atom within the first 10 MB"));
7051 ret = GST_FLOW_ERROR;
7057 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
7062 query = gst_query_new_scheduling ();
7064 if (!gst_pad_peer_query (sinkpad, query)) {
7065 gst_query_unref (query);
7069 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
7070 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
7071 gst_query_unref (query);
7076 GST_DEBUG_OBJECT (sinkpad, "activating pull");
7077 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
7081 GST_DEBUG_OBJECT (sinkpad, "activating push");
7082 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
7087 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
7088 GstPadMode mode, gboolean active)
7091 GstQTDemux *demux = GST_QTDEMUX (parent);
7094 case GST_PAD_MODE_PUSH:
7095 demux->pullbased = FALSE;
7098 case GST_PAD_MODE_PULL:
7100 demux->pullbased = TRUE;
7101 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
7104 res = gst_pad_stop_task (sinkpad);
7116 qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
7122 memset (&z, 0, sizeof (z));
7127 if ((ret = inflateInit (&z)) != Z_OK) {
7128 GST_ERROR ("inflateInit() returned %d", ret);
7132 z.next_in = z_buffer;
7133 z.avail_in = z_length;
7135 buffer = (guint8 *) g_malloc (*length);
7136 z.avail_out = *length;
7137 z.next_out = (Bytef *) buffer;
7139 ret = inflate (&z, Z_NO_FLUSH);
7140 if (ret == Z_STREAM_END) {
7142 } else if (ret != Z_OK) {
7143 GST_WARNING ("inflate() returned %d", ret);
7148 buffer = (guint8 *) g_realloc (buffer, *length);
7149 z.next_out = (Bytef *) (buffer + z.total_out);
7150 z.avail_out += 4096;
7151 } while (z.avail_in > 0);
7153 if (ret != Z_STREAM_END) {
7158 *length = z.total_out;
7165 #endif /* HAVE_ZLIB */
7168 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
7172 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
7174 /* counts as header data */
7175 qtdemux->header_size += length;
7177 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
7178 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
7180 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
7187 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
7188 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
7189 if (dcom == NULL || cmvd == NULL)
7190 goto invalid_compression;
7192 dcom_len = QT_UINT32 (dcom->data);
7194 goto invalid_compression;
7196 method = QT_FOURCC ((guint8 *) dcom->data + 8);
7200 guint uncompressed_length;
7201 guint compressed_length;
7205 cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
7207 goto invalid_compression;
7209 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
7210 compressed_length = cmvd_len - 12;
7211 GST_LOG ("length = %u", uncompressed_length);
7214 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
7215 compressed_length, &uncompressed_length);
7218 qtdemux->moov_node_compressed = qtdemux->moov_node;
7219 qtdemux->moov_node = g_node_new (buf);
7221 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
7222 uncompressed_length);
7226 #endif /* HAVE_ZLIB */
7228 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
7229 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
7236 invalid_compression:
7238 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
7244 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
7247 while (G_UNLIKELY (buf < end)) {
7251 if (G_UNLIKELY (buf + 4 > end)) {
7252 GST_LOG_OBJECT (qtdemux, "buffer overrun");
7255 len = QT_UINT32 (buf);
7256 if (G_UNLIKELY (len == 0)) {
7257 GST_LOG_OBJECT (qtdemux, "empty container");
7260 if (G_UNLIKELY (len < 8)) {
7261 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
7264 if (G_UNLIKELY (len > (end - buf))) {
7265 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
7266 (gint) (end - buf));
7270 child = g_node_new ((guint8 *) buf);
7271 g_node_append (node, child);
7272 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
7273 qtdemux_parse_node (qtdemux, child, buf, len);
7281 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
7284 int len = QT_UINT32 (xdxt->data);
7285 guint8 *buf = xdxt->data;
7286 guint8 *end = buf + len;
7289 /* skip size and type */
7297 size = QT_UINT32 (buf);
7298 type = QT_FOURCC (buf + 4);
7300 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
7302 if (buf + size > end || size <= 0)
7308 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
7309 GST_FOURCC_ARGS (type));
7313 buffer = gst_buffer_new_and_alloc (size);
7314 gst_buffer_fill (buffer, 0, buf, size);
7315 stream->buffers = g_slist_append (stream->buffers, buffer);
7316 GST_LOG_OBJECT (qtdemux, "parsing theora header");
7319 buffer = gst_buffer_new_and_alloc (size);
7320 gst_buffer_fill (buffer, 0, buf, size);
7321 stream->buffers = g_slist_append (stream->buffers, buffer);
7322 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
7325 buffer = gst_buffer_new_and_alloc (size);
7326 gst_buffer_fill (buffer, 0, buf, size);
7327 stream->buffers = g_slist_append (stream->buffers, buffer);
7328 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
7331 GST_WARNING_OBJECT (qtdemux,
7332 "unknown theora cookie %" GST_FOURCC_FORMAT,
7333 GST_FOURCC_ARGS (type));
7342 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
7346 guint32 node_length = 0;
7347 const QtNodeType *type;
7350 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
7352 if (G_UNLIKELY (length < 8))
7353 goto not_enough_data;
7355 node_length = QT_UINT32 (buffer);
7356 fourcc = QT_FOURCC (buffer + 4);
7358 /* ignore empty nodes */
7359 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
7362 type = qtdemux_type_get (fourcc);
7364 end = buffer + length;
7366 GST_LOG_OBJECT (qtdemux,
7367 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
7368 GST_FOURCC_ARGS (fourcc), node_length, type->name);
7370 if (node_length > length)
7371 goto broken_atom_size;
7373 if (type->flags & QT_FLAG_CONTAINER) {
7374 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
7379 if (node_length < 20) {
7380 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
7383 GST_DEBUG_OBJECT (qtdemux,
7384 "parsing stsd (sample table, sample description) atom");
7385 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
7386 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7397 /* also read alac (or whatever) in stead of mp4a in the following,
7398 * since a similar layout is used in other cases as well */
7399 if (fourcc == FOURCC_mp4a)
7401 else if (fourcc == FOURCC_fLaC)
7406 /* There are two things we might encounter here: a true mp4a atom, and
7407 an mp4a entry in an stsd atom. The latter is what we're interested
7408 in, and it looks like an atom, but isn't really one. The true mp4a
7409 atom is short, so we detect it based on length here. */
7410 if (length < min_size) {
7411 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7412 GST_FOURCC_ARGS (fourcc));
7416 /* 'version' here is the sound sample description version. Types 0 and
7417 1 are documented in the QTFF reference, but type 2 is not: it's
7418 described in Apple header files instead (struct SoundDescriptionV2
7420 version = QT_UINT16 (buffer + 16);
7422 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
7423 GST_FOURCC_ARGS (fourcc), version);
7425 /* parse any esds descriptors */
7437 GST_WARNING_OBJECT (qtdemux,
7438 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
7439 GST_FOURCC_ARGS (fourcc), version);
7444 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7470 /* codec_data is contained inside these atoms, which all have
7471 * the same format. */
7472 /* video sample description size is 86 bytes without extension.
7473 * node_length have to be bigger than 86 bytes because video sample
7474 * description can include extenstions such as esds, fiel, glbl, etc. */
7475 if (node_length < 86) {
7476 GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
7477 " sample description length too short (%u < 86)",
7478 GST_FOURCC_ARGS (fourcc), node_length);
7482 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
7483 GST_FOURCC_ARGS (fourcc));
7485 /* version (2 bytes) : this is set to 0, unless a compressor has changed
7487 * revision level (2 bytes) : must be set to 0. */
7488 version = QT_UINT32 (buffer + 16);
7489 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
7491 /* compressor name : PASCAL string and informative purposes
7492 * first byte : the number of bytes to be displayed.
7493 * it has to be less than 32 because it is reserved
7494 * space of 32 bytes total including itself. */
7495 str_len = QT_UINT8 (buffer + 50);
7497 GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
7498 (char *) buffer + 51);
7500 GST_WARNING_OBJECT (qtdemux,
7501 "compressorname length too big (%u > 31)", str_len);
7503 GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
7505 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
7510 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
7511 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
7516 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
7517 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
7518 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7527 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7528 GST_FOURCC_ARGS (fourcc));
7532 version = QT_UINT32 (buffer + 12);
7533 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
7540 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
7545 if (length < offset) {
7546 GST_WARNING_OBJECT (qtdemux,
7547 "skipping too small %" GST_FOURCC_FORMAT " box",
7548 GST_FOURCC_ARGS (fourcc));
7551 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7557 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
7562 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
7567 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
7571 if (!strcmp (type->name, "unknown"))
7572 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
7576 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
7577 GST_FOURCC_ARGS (fourcc));
7583 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7584 (_("This file is corrupt and cannot be played.")),
7585 ("Not enough data for an atom header, got only %u bytes", length));
7590 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7591 (_("This file is corrupt and cannot be played.")),
7592 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
7593 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
7600 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
7604 guint32 child_fourcc;
7606 for (child = g_node_first_child (node); child;
7607 child = g_node_next_sibling (child)) {
7608 buffer = (guint8 *) child->data;
7610 child_fourcc = QT_FOURCC (buffer + 4);
7612 if (G_UNLIKELY (child_fourcc == fourcc)) {
7620 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
7621 GstByteReader * parser)
7625 guint32 child_fourcc, child_len;
7627 for (child = g_node_first_child (node); child;
7628 child = g_node_next_sibling (child)) {
7629 buffer = (guint8 *) child->data;
7631 child_len = QT_UINT32 (buffer);
7632 child_fourcc = QT_FOURCC (buffer + 4);
7634 if (G_UNLIKELY (child_fourcc == fourcc)) {
7635 if (G_UNLIKELY (child_len < (4 + 4)))
7637 /* FIXME: must verify if atom length < parent atom length */
7638 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7646 qtdemux_tree_get_child_by_index (GNode * node, guint index)
7648 return g_node_nth_child (node, index);
7652 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
7653 GstByteReader * parser)
7657 guint32 child_fourcc, child_len;
7659 for (child = g_node_next_sibling (node); child;
7660 child = g_node_next_sibling (child)) {
7661 buffer = (guint8 *) child->data;
7663 child_fourcc = QT_FOURCC (buffer + 4);
7665 if (child_fourcc == fourcc) {
7667 child_len = QT_UINT32 (buffer);
7668 if (G_UNLIKELY (child_len < (4 + 4)))
7670 /* FIXME: must verify if atom length < parent atom length */
7671 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7680 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
7682 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
7686 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
7688 /* FIXME: This can only reliably work if demuxers have a
7689 * separate streaming thread per srcpad. This should be
7690 * done in a demuxer base class, which integrates parts
7693 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
7698 query = gst_query_new_allocation (stream->caps, FALSE);
7700 if (!gst_pad_peer_query (stream->pad, query)) {
7701 /* not a problem, just debug a little */
7702 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
7705 if (stream->allocator)
7706 gst_object_unref (stream->allocator);
7708 if (gst_query_get_n_allocation_params (query) > 0) {
7709 /* try the allocator */
7710 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
7712 stream->use_allocator = TRUE;
7714 stream->allocator = NULL;
7715 gst_allocation_params_init (&stream->params);
7716 stream->use_allocator = FALSE;
7718 gst_query_unref (query);
7723 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
7724 QtDemuxStream * stream)
7727 const gchar *selected_system;
7729 g_return_val_if_fail (qtdemux != NULL, FALSE);
7730 g_return_val_if_fail (stream != NULL, FALSE);
7731 g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1,
7734 if (stream->protection_scheme_type != FOURCC_cenc) {
7735 GST_ERROR_OBJECT (qtdemux, "unsupported protection scheme");
7738 if (qtdemux->protection_system_ids == NULL) {
7739 GST_ERROR_OBJECT (qtdemux, "stream is protected using cenc, but no "
7740 "cenc protection system information has been found");
7743 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
7744 selected_system = gst_protection_select_system ((const gchar **)
7745 qtdemux->protection_system_ids->pdata);
7746 g_ptr_array_remove_index (qtdemux->protection_system_ids,
7747 qtdemux->protection_system_ids->len - 1);
7748 if (!selected_system) {
7749 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
7750 "suitable decryptor element has been found");
7754 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
7755 if (!gst_structure_has_name (s, "application/x-cenc")) {
7756 gst_structure_set (s,
7757 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
7758 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
7760 gst_structure_set_name (s, "application/x-cenc");
7766 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
7768 if (stream->subtype == FOURCC_vide) {
7769 /* fps is calculated base on the duration of the average framerate since
7770 * qt does not have a fixed framerate. */
7771 gboolean fps_available = TRUE;
7773 if ((stream->n_samples == 1 && stream->first_duration == 0)
7774 || (qtdemux->fragmented && stream->n_samples_moof == 1)) {
7776 CUR_STREAM (stream)->fps_n = 0;
7777 CUR_STREAM (stream)->fps_d = 1;
7779 if (stream->duration == 0 || stream->n_samples < 2) {
7780 CUR_STREAM (stream)->fps_n = stream->timescale;
7781 CUR_STREAM (stream)->fps_d = 1;
7782 fps_available = FALSE;
7784 GstClockTime avg_duration;
7788 /* duration and n_samples can be updated for fragmented format
7789 * so, framerate of fragmented format is calculated using data in a moof */
7790 if (qtdemux->fragmented && stream->n_samples_moof > 0
7791 && stream->duration_moof > 0) {
7792 n_samples = stream->n_samples_moof;
7793 duration = stream->duration_moof;
7795 n_samples = stream->n_samples;
7796 duration = stream->duration;
7799 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
7800 /* stream->duration is guint64, timescale, n_samples are guint32 */
7802 gst_util_uint64_scale_round (duration -
7803 stream->first_duration, GST_SECOND,
7804 (guint64) (stream->timescale) * (n_samples - 1));
7806 GST_LOG_OBJECT (qtdemux,
7807 "Calculating avg sample duration based on stream (or moof) duration %"
7809 " minus first sample %u, leaving %d samples gives %"
7810 GST_TIME_FORMAT, duration, stream->first_duration,
7811 n_samples - 1, GST_TIME_ARGS (avg_duration));
7813 gst_video_guess_framerate (avg_duration, &CUR_STREAM (stream)->fps_n,
7814 &CUR_STREAM (stream)->fps_d);
7816 GST_DEBUG_OBJECT (qtdemux,
7817 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
7818 stream->timescale, CUR_STREAM (stream)->fps_n,
7819 CUR_STREAM (stream)->fps_d);
7823 if (CUR_STREAM (stream)->caps) {
7824 CUR_STREAM (stream)->caps =
7825 gst_caps_make_writable (CUR_STREAM (stream)->caps);
7827 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7828 "width", G_TYPE_INT, CUR_STREAM (stream)->width,
7829 "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL);
7831 /* set framerate if calculated framerate is reliable */
7832 if (fps_available) {
7833 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7834 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
7835 CUR_STREAM (stream)->fps_d, NULL);
7838 /* calculate pixel-aspect-ratio using display width and height */
7839 GST_DEBUG_OBJECT (qtdemux,
7840 "video size %dx%d, target display size %dx%d",
7841 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height,
7842 stream->display_width, stream->display_height);
7843 /* qt file might have pasp atom */
7844 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
7845 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w,
7846 CUR_STREAM (stream)->par_h);
7847 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
7848 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
7849 CUR_STREAM (stream)->par_h, NULL);
7850 } else if (stream->display_width > 0 && stream->display_height > 0
7851 && CUR_STREAM (stream)->width > 0
7852 && CUR_STREAM (stream)->height > 0) {
7855 /* calculate the pixel aspect ratio using the display and pixel w/h */
7856 n = stream->display_width * CUR_STREAM (stream)->height;
7857 d = stream->display_height * CUR_STREAM (stream)->width;
7860 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
7861 CUR_STREAM (stream)->par_w = n;
7862 CUR_STREAM (stream)->par_h = d;
7863 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
7864 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
7865 CUR_STREAM (stream)->par_h, NULL);
7868 if (CUR_STREAM (stream)->interlace_mode > 0) {
7869 if (CUR_STREAM (stream)->interlace_mode == 1) {
7870 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
7871 G_TYPE_STRING, "progressive", NULL);
7872 } else if (CUR_STREAM (stream)->interlace_mode == 2) {
7873 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
7874 G_TYPE_STRING, "interleaved", NULL);
7875 if (CUR_STREAM (stream)->field_order == 9) {
7876 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
7877 G_TYPE_STRING, "top-field-first", NULL);
7878 } else if (CUR_STREAM (stream)->field_order == 14) {
7879 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
7880 G_TYPE_STRING, "bottom-field-first", NULL);
7885 /* Create incomplete colorimetry here if needed */
7886 if (CUR_STREAM (stream)->colorimetry.range ||
7887 CUR_STREAM (stream)->colorimetry.matrix ||
7888 CUR_STREAM (stream)->colorimetry.transfer
7889 || CUR_STREAM (stream)->colorimetry.primaries) {
7890 gchar *colorimetry =
7891 gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry);
7892 gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry",
7893 G_TYPE_STRING, colorimetry, NULL);
7894 g_free (colorimetry);
7897 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
7898 guint par_w = 1, par_h = 1;
7900 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
7901 par_w = CUR_STREAM (stream)->par_w;
7902 par_h = CUR_STREAM (stream)->par_h;
7905 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
7906 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w,
7908 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
7911 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7912 "multiview-mode", G_TYPE_STRING,
7913 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
7914 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
7915 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
7920 else if (stream->subtype == FOURCC_soun) {
7921 if (CUR_STREAM (stream)->caps) {
7922 CUR_STREAM (stream)->caps =
7923 gst_caps_make_writable (CUR_STREAM (stream)->caps);
7924 if (CUR_STREAM (stream)->rate > 0)
7925 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7926 "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL);
7927 if (CUR_STREAM (stream)->n_channels > 0)
7928 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7929 "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL);
7930 if (CUR_STREAM (stream)->n_channels > 2) {
7931 /* FIXME: Need to parse the 'chan' atom to get channel layouts
7932 * correctly; this is just the minimum we can do - assume
7933 * we don't actually have any channel positions. */
7934 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7935 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
7941 GstCaps *prev_caps = NULL;
7943 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
7944 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
7945 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
7946 gst_pad_set_active (stream->pad, TRUE);
7948 gst_pad_use_fixed_caps (stream->pad);
7950 if (stream->protected) {
7951 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
7952 GST_ERROR_OBJECT (qtdemux,
7953 "Failed to configure protected stream caps.");
7958 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
7959 CUR_STREAM (stream)->caps);
7960 if (stream->new_stream) {
7963 GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
7966 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
7969 gst_event_parse_stream_flags (event, &stream_flags);
7970 if (gst_event_parse_group_id (event, &qtdemux->group_id))
7971 qtdemux->have_group_id = TRUE;
7973 qtdemux->have_group_id = FALSE;
7974 gst_event_unref (event);
7975 } else if (!qtdemux->have_group_id) {
7976 qtdemux->have_group_id = TRUE;
7977 qtdemux->group_id = gst_util_group_id_next ();
7980 stream->new_stream = FALSE;
7982 gst_pad_create_stream_id_printf (stream->pad,
7983 GST_ELEMENT_CAST (qtdemux), "%03u", stream->track_id);
7984 event = gst_event_new_stream_start (stream_id);
7985 if (qtdemux->have_group_id)
7986 gst_event_set_group_id (event, qtdemux->group_id);
7987 if (stream->disabled)
7988 stream_flags |= GST_STREAM_FLAG_UNSELECT;
7989 if (CUR_STREAM (stream)->sparse) {
7990 stream_flags |= GST_STREAM_FLAG_SPARSE;
7992 stream_flags &= ~GST_STREAM_FLAG_SPARSE;
7994 gst_event_set_stream_flags (event, stream_flags);
7995 gst_pad_push_event (stream->pad, event);
7999 prev_caps = gst_pad_get_current_caps (stream->pad);
8001 if (CUR_STREAM (stream)->caps) {
8003 || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) {
8004 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8005 CUR_STREAM (stream)->caps);
8006 gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps);
8008 GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
8011 GST_WARNING_OBJECT (qtdemux, "stream without caps");
8015 gst_caps_unref (prev_caps);
8016 stream->new_caps = FALSE;
8022 gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
8023 QtDemuxStream * stream)
8025 if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id)
8028 GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'",
8029 stream->cur_stsd_entry_index, stream->stsd_sample_description_id);
8030 if (G_UNLIKELY (stream->stsd_sample_description_id >=
8031 stream->stsd_entries_length)) {
8032 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
8033 (_("This file is invalid and cannot be played.")),
8034 ("New sample description id is out of bounds (%d >= %d)",
8035 stream->stsd_sample_description_id, stream->stsd_entries_length));
8037 stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
8038 stream->new_caps = TRUE;
8043 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
8044 QtDemuxStream * stream, GstTagList * list)
8046 gboolean ret = TRUE;
8047 /* consistent default for push based mode */
8048 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
8050 if (stream->subtype == FOURCC_vide) {
8051 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8054 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8057 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8058 gst_object_unref (stream->pad);
8064 qtdemux->n_video_streams++;
8065 } else if (stream->subtype == FOURCC_soun) {
8066 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
8069 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
8071 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8072 gst_object_unref (stream->pad);
8077 qtdemux->n_audio_streams++;
8078 } else if (stream->subtype == FOURCC_strm) {
8079 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
8080 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
8081 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
8082 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
8085 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
8087 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8088 gst_object_unref (stream->pad);
8093 qtdemux->n_sub_streams++;
8094 } else if (CUR_STREAM (stream)->caps) {
8095 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8098 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8100 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8101 gst_object_unref (stream->pad);
8106 qtdemux->n_video_streams++;
8108 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
8115 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
8116 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
8117 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
8118 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
8120 if (stream->stream_tags)
8121 gst_tag_list_unref (stream->stream_tags);
8122 stream->stream_tags = list;
8124 /* global tags go on each pad anyway */
8125 stream->send_global_tags = TRUE;
8126 /* send upstream GST_EVENT_PROTECTION events that were received before
8127 this source pad was created */
8128 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
8129 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
8133 gst_tag_list_unref (list);
8137 /* find next atom with @fourcc starting at @offset */
8138 static GstFlowReturn
8139 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
8140 guint64 * length, guint32 fourcc)
8146 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
8147 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
8153 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
8154 if (G_UNLIKELY (ret != GST_FLOW_OK))
8156 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
8159 gst_buffer_unref (buf);
8162 gst_buffer_map (buf, &map, GST_MAP_READ);
8163 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
8164 gst_buffer_unmap (buf, &map);
8165 gst_buffer_unref (buf);
8167 if (G_UNLIKELY (*length == 0)) {
8168 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
8169 ret = GST_FLOW_ERROR;
8173 if (lfourcc == fourcc) {
8174 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
8178 GST_LOG_OBJECT (qtdemux,
8179 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
8180 GST_FOURCC_ARGS (fourcc), *offset);
8189 /* might simply have had last one */
8190 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
8195 /* should only do something in pull mode */
8196 /* call with OBJECT lock */
8197 static GstFlowReturn
8198 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
8200 guint64 length, offset;
8201 GstBuffer *buf = NULL;
8202 GstFlowReturn ret = GST_FLOW_OK;
8203 GstFlowReturn res = GST_FLOW_OK;
8206 offset = qtdemux->moof_offset;
8207 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
8210 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8211 return GST_FLOW_EOS;
8214 /* best not do pull etc with lock held */
8215 GST_OBJECT_UNLOCK (qtdemux);
8217 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8218 if (ret != GST_FLOW_OK)
8221 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
8222 if (G_UNLIKELY (ret != GST_FLOW_OK))
8224 gst_buffer_map (buf, &map, GST_MAP_READ);
8225 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
8226 gst_buffer_unmap (buf, &map);
8227 gst_buffer_unref (buf);
8232 gst_buffer_unmap (buf, &map);
8233 gst_buffer_unref (buf);
8237 /* look for next moof */
8238 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8239 if (G_UNLIKELY (ret != GST_FLOW_OK))
8243 GST_OBJECT_LOCK (qtdemux);
8245 qtdemux->moof_offset = offset;
8251 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
8253 res = GST_FLOW_ERROR;
8258 /* maybe upstream temporarily flushing */
8259 if (ret != GST_FLOW_FLUSHING) {
8260 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8263 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
8264 /* resume at current position next time */
8271 /* initialise bytereaders for stbl sub-atoms */
8273 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
8275 stream->stbl_index = -1; /* no samples have yet been parsed */
8276 stream->sample_index = -1;
8278 /* time-to-sample atom */
8279 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
8282 /* copy atom data into a new buffer for later use */
8283 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
8285 /* skip version + flags */
8286 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
8287 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
8289 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
8291 /* make sure there's enough data */
8292 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
8293 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
8294 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
8295 stream->n_sample_times);
8296 if (!stream->n_sample_times)
8300 /* sync sample atom */
8301 stream->stps_present = FALSE;
8302 if ((stream->stss_present =
8303 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
8304 &stream->stss) ? TRUE : FALSE) == TRUE) {
8305 /* copy atom data into a new buffer for later use */
8306 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
8308 /* skip version + flags */
8309 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
8310 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
8313 if (stream->n_sample_syncs) {
8314 /* make sure there's enough data */
8315 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
8319 /* partial sync sample atom */
8320 if ((stream->stps_present =
8321 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
8322 &stream->stps) ? TRUE : FALSE) == TRUE) {
8323 /* copy atom data into a new buffer for later use */
8324 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
8326 /* skip version + flags */
8327 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
8328 !gst_byte_reader_get_uint32_be (&stream->stps,
8329 &stream->n_sample_partial_syncs))
8332 /* if there are no entries, the stss table contains the real
8334 if (stream->n_sample_partial_syncs) {
8335 /* make sure there's enough data */
8336 if (!qt_atom_parser_has_chunks (&stream->stps,
8337 stream->n_sample_partial_syncs, 4))
8344 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
8347 /* copy atom data into a new buffer for later use */
8348 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
8350 /* skip version + flags */
8351 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
8352 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
8355 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
8358 if (!stream->n_samples)
8361 /* sample-to-chunk atom */
8362 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
8365 /* copy atom data into a new buffer for later use */
8366 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
8368 /* skip version + flags */
8369 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
8370 !gst_byte_reader_get_uint32_be (&stream->stsc,
8371 &stream->n_samples_per_chunk))
8374 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
8375 stream->n_samples_per_chunk);
8377 /* make sure there's enough data */
8378 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
8384 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
8385 stream->co_size = sizeof (guint32);
8386 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
8388 stream->co_size = sizeof (guint64);
8392 /* copy atom data into a new buffer for later use */
8393 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
8395 /* skip version + flags */
8396 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
8399 /* chunks_are_samples == TRUE means treat chunks as samples */
8400 stream->chunks_are_samples = stream->sample_size
8401 && !CUR_STREAM (stream)->sampled;
8402 if (stream->chunks_are_samples) {
8403 /* treat chunks as samples */
8404 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
8407 /* skip number of entries */
8408 if (!gst_byte_reader_skip (&stream->stco, 4))
8411 /* make sure there are enough data in the stsz atom */
8412 if (!stream->sample_size) {
8413 /* different sizes for each sample */
8414 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
8419 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
8420 stream->n_samples, (guint) sizeof (QtDemuxSample),
8421 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
8423 if (stream->n_samples >=
8424 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
8425 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
8426 "be larger than %uMB (broken file?)", stream->n_samples,
8427 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
8431 g_assert (stream->samples == NULL);
8432 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
8433 if (!stream->samples) {
8434 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
8439 /* composition time-to-sample */
8440 if ((stream->ctts_present =
8441 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
8442 &stream->ctts) ? TRUE : FALSE) == TRUE) {
8443 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
8445 /* copy atom data into a new buffer for later use */
8446 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
8448 /* skip version + flags */
8449 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
8450 || !gst_byte_reader_get_uint32_be (&stream->ctts,
8451 &stream->n_composition_times))
8454 /* make sure there's enough data */
8455 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
8459 /* This is optional, if missing we iterate the ctts */
8460 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
8461 if (!gst_byte_reader_skip (&cslg, 1 + 3)
8462 || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
8463 g_free ((gpointer) cslg.data);
8467 gint32 cslg_least = 0;
8468 guint num_entries, pos;
8471 pos = gst_byte_reader_get_pos (&stream->ctts);
8472 num_entries = stream->n_composition_times;
8474 stream->cslg_shift = 0;
8476 for (i = 0; i < num_entries; i++) {
8479 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
8480 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8482 if (offset < cslg_least)
8483 cslg_least = offset;
8487 stream->cslg_shift = ABS (cslg_least);
8489 stream->cslg_shift = 0;
8491 /* reset the reader so we can generate sample table */
8492 gst_byte_reader_set_pos (&stream->ctts, pos);
8495 /* Ensure the cslg_shift value is consistent so we can use it
8496 * unconditionnally to produce TS and Segment */
8497 stream->cslg_shift = 0;
8504 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8505 (_("This file is corrupt and cannot be played.")), (NULL));
8510 gst_qtdemux_stbl_free (stream);
8511 if (!qtdemux->fragmented) {
8512 /* not quite good */
8513 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
8516 /* may pick up samples elsewhere */
8522 /* collect samples from the next sample to be parsed up to sample @n for @stream
8523 * by reading the info from @stbl
8525 * This code can be executed from both the streaming thread and the seeking
8526 * thread so it takes the object lock to protect itself
8529 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
8532 QtDemuxSample *samples, *first, *cur, *last;
8533 guint32 n_samples_per_chunk;
8536 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
8537 GST_FOURCC_FORMAT ", pad %s",
8538 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
8539 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
8541 n_samples = stream->n_samples;
8544 goto out_of_samples;
8546 GST_OBJECT_LOCK (qtdemux);
8547 if (n <= stream->stbl_index)
8548 goto already_parsed;
8550 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
8552 if (!stream->stsz.data) {
8553 /* so we already parsed and passed all the moov samples;
8554 * onto fragmented ones */
8555 g_assert (qtdemux->fragmented);
8559 /* pointer to the sample table */
8560 samples = stream->samples;
8562 /* starts from -1, moves to the next sample index to parse */
8563 stream->stbl_index++;
8565 /* keep track of the first and last sample to fill */
8566 first = &samples[stream->stbl_index];
8569 if (!stream->chunks_are_samples) {
8570 /* set the sample sizes */
8571 if (stream->sample_size == 0) {
8572 /* different sizes for each sample */
8573 for (cur = first; cur <= last; cur++) {
8574 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
8575 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
8576 (guint) (cur - samples), cur->size);
8579 /* samples have the same size */
8580 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
8581 for (cur = first; cur <= last; cur++)
8582 cur->size = stream->sample_size;
8586 n_samples_per_chunk = stream->n_samples_per_chunk;
8589 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
8592 if (stream->stsc_chunk_index >= stream->last_chunk
8593 || stream->stsc_chunk_index < stream->first_chunk) {
8594 stream->first_chunk =
8595 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8596 stream->samples_per_chunk =
8597 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8599 stream->stsd_sample_description_id =
8600 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
8602 /* chunk numbers are counted from 1 it seems */
8603 if (G_UNLIKELY (stream->first_chunk == 0))
8606 --stream->first_chunk;
8608 /* the last chunk of each entry is calculated by taking the first chunk
8609 * of the next entry; except if there is no next, where we fake it with
8611 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
8612 stream->last_chunk = G_MAXUINT32;
8614 stream->last_chunk =
8615 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
8616 if (G_UNLIKELY (stream->last_chunk == 0))
8619 --stream->last_chunk;
8622 GST_LOG_OBJECT (qtdemux,
8623 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
8624 "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
8625 stream->samples_per_chunk, stream->stsd_sample_description_id);
8627 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
8630 if (stream->last_chunk != G_MAXUINT32) {
8631 if (!qt_atom_parser_peek_sub (&stream->stco,
8632 stream->first_chunk * stream->co_size,
8633 (stream->last_chunk - stream->first_chunk) * stream->co_size,
8638 stream->co_chunk = stream->stco;
8639 if (!gst_byte_reader_skip (&stream->co_chunk,
8640 stream->first_chunk * stream->co_size))
8644 stream->stsc_chunk_index = stream->first_chunk;
8647 last_chunk = stream->last_chunk;
8649 if (stream->chunks_are_samples) {
8650 cur = &samples[stream->stsc_chunk_index];
8652 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8655 stream->stsc_chunk_index = j;
8660 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
8663 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
8664 "%" G_GUINT64_FORMAT, j, cur->offset);
8666 if (CUR_STREAM (stream)->samples_per_frame > 0 &&
8667 CUR_STREAM (stream)->bytes_per_frame > 0) {
8669 (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
8670 CUR_STREAM (stream)->samples_per_frame *
8671 CUR_STREAM (stream)->bytes_per_frame;
8673 cur->size = stream->samples_per_chunk;
8676 GST_DEBUG_OBJECT (qtdemux,
8677 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
8678 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
8679 stream->stco_sample_index)), cur->size);
8681 cur->timestamp = stream->stco_sample_index;
8682 cur->duration = stream->samples_per_chunk;
8683 cur->keyframe = TRUE;
8686 stream->stco_sample_index += stream->samples_per_chunk;
8688 stream->stsc_chunk_index = j;
8690 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8691 guint32 samples_per_chunk;
8692 guint64 chunk_offset;
8694 if (!stream->stsc_sample_index
8695 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
8696 &stream->chunk_offset))
8699 samples_per_chunk = stream->samples_per_chunk;
8700 chunk_offset = stream->chunk_offset;
8702 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
8703 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
8704 G_GUINT64_FORMAT " and size %d",
8705 (guint) (cur - samples), chunk_offset, cur->size);
8707 cur->offset = chunk_offset;
8708 chunk_offset += cur->size;
8711 if (G_UNLIKELY (cur > last)) {
8713 stream->stsc_sample_index = k + 1;
8714 stream->chunk_offset = chunk_offset;
8715 stream->stsc_chunk_index = j;
8719 stream->stsc_sample_index = 0;
8721 stream->stsc_chunk_index = j;
8723 stream->stsc_index++;
8726 if (stream->chunks_are_samples)
8730 guint32 n_sample_times;
8732 n_sample_times = stream->n_sample_times;
8735 for (i = stream->stts_index; i < n_sample_times; i++) {
8736 guint32 stts_samples;
8737 gint32 stts_duration;
8740 if (stream->stts_sample_index >= stream->stts_samples
8741 || !stream->stts_sample_index) {
8743 stream->stts_samples =
8744 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8745 stream->stts_duration =
8746 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8748 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
8749 i, stream->stts_samples, stream->stts_duration);
8751 stream->stts_sample_index = 0;
8754 stts_samples = stream->stts_samples;
8755 stts_duration = stream->stts_duration;
8756 stts_time = stream->stts_time;
8758 for (j = stream->stts_sample_index; j < stts_samples; j++) {
8759 GST_DEBUG_OBJECT (qtdemux,
8760 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
8761 (guint) (cur - samples), j,
8762 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
8764 cur->timestamp = stts_time;
8765 cur->duration = stts_duration;
8767 /* avoid 32-bit wrap-around,
8768 * but still mind possible 'negative' duration */
8769 stts_time += (gint64) stts_duration;
8772 if (G_UNLIKELY (cur > last)) {
8774 stream->stts_time = stts_time;
8775 stream->stts_sample_index = j + 1;
8776 if (stream->stts_sample_index >= stream->stts_samples)
8777 stream->stts_index++;
8781 stream->stts_sample_index = 0;
8782 stream->stts_time = stts_time;
8783 stream->stts_index++;
8785 /* fill up empty timestamps with the last timestamp, this can happen when
8786 * the last samples do not decode and so we don't have timestamps for them.
8787 * We however look at the last timestamp to estimate the track length so we
8788 * need something in here. */
8789 for (; cur < last; cur++) {
8790 GST_DEBUG_OBJECT (qtdemux,
8791 "fill sample %d: timestamp %" GST_TIME_FORMAT,
8792 (guint) (cur - samples),
8793 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
8794 cur->timestamp = stream->stts_time;
8800 /* sample sync, can be NULL */
8801 if (stream->stss_present == TRUE) {
8802 guint32 n_sample_syncs;
8804 n_sample_syncs = stream->n_sample_syncs;
8806 if (!n_sample_syncs) {
8807 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
8808 stream->all_keyframe = TRUE;
8810 for (i = stream->stss_index; i < n_sample_syncs; i++) {
8811 /* note that the first sample is index 1, not 0 */
8814 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
8816 if (G_LIKELY (index > 0 && index <= n_samples)) {
8818 samples[index].keyframe = TRUE;
8819 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8820 /* and exit if we have enough samples */
8821 if (G_UNLIKELY (index >= n)) {
8828 stream->stss_index = i;
8831 /* stps marks partial sync frames like open GOP I-Frames */
8832 if (stream->stps_present == TRUE) {
8833 guint32 n_sample_partial_syncs;
8835 n_sample_partial_syncs = stream->n_sample_partial_syncs;
8837 /* if there are no entries, the stss table contains the real
8839 if (n_sample_partial_syncs) {
8840 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
8841 /* note that the first sample is index 1, not 0 */
8844 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
8846 if (G_LIKELY (index > 0 && index <= n_samples)) {
8848 samples[index].keyframe = TRUE;
8849 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8850 /* and exit if we have enough samples */
8851 if (G_UNLIKELY (index >= n)) {
8858 stream->stps_index = i;
8862 /* no stss, all samples are keyframes */
8863 stream->all_keyframe = TRUE;
8864 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
8869 /* composition time to sample */
8870 if (stream->ctts_present == TRUE) {
8871 guint32 n_composition_times;
8873 gint32 ctts_soffset;
8875 /* Fill in the pts_offsets */
8877 n_composition_times = stream->n_composition_times;
8879 for (i = stream->ctts_index; i < n_composition_times; i++) {
8880 if (stream->ctts_sample_index >= stream->ctts_count
8881 || !stream->ctts_sample_index) {
8882 stream->ctts_count =
8883 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
8884 stream->ctts_soffset =
8885 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8886 stream->ctts_sample_index = 0;
8889 ctts_count = stream->ctts_count;
8890 ctts_soffset = stream->ctts_soffset;
8892 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
8893 cur->pts_offset = ctts_soffset;
8896 if (G_UNLIKELY (cur > last)) {
8898 stream->ctts_sample_index = j + 1;
8902 stream->ctts_sample_index = 0;
8903 stream->ctts_index++;
8907 stream->stbl_index = n;
8908 /* if index has been completely parsed, free data that is no-longer needed */
8909 if (n + 1 == stream->n_samples) {
8910 gst_qtdemux_stbl_free (stream);
8911 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
8912 if (qtdemux->pullbased) {
8913 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
8914 while (n + 1 == stream->n_samples)
8915 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
8919 GST_OBJECT_UNLOCK (qtdemux);
8926 GST_LOG_OBJECT (qtdemux,
8927 "Tried to parse up to sample %u but this sample has already been parsed",
8929 /* if fragmented, there may be more */
8930 if (qtdemux->fragmented && n == stream->stbl_index)
8932 GST_OBJECT_UNLOCK (qtdemux);
8938 GST_LOG_OBJECT (qtdemux,
8939 "Tried to parse up to sample %u but there are only %u samples", n + 1,
8941 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8942 (_("This file is corrupt and cannot be played.")), (NULL));
8947 GST_OBJECT_UNLOCK (qtdemux);
8948 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8949 (_("This file is corrupt and cannot be played.")), (NULL));
8954 /* collect all segment info for @stream.
8957 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
8961 /* accept edts if they contain gaps at start and there is only
8962 * one media segment */
8963 gboolean allow_pushbased_edts = TRUE;
8964 gint media_segments_count = 0;
8966 /* parse and prepare segment info from the edit list */
8967 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
8968 stream->n_segments = 0;
8969 stream->segments = NULL;
8970 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
8973 gint i, count, entry_size;
8976 const guint8 *buffer;
8980 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
8981 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
8984 buffer = elst->data;
8986 size = QT_UINT32 (buffer);
8987 /* version, flags, n_segments */
8989 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
8992 version = QT_UINT8 (buffer + 8);
8993 entry_size = (version == 1) ? 20 : 12;
8995 n_segments = QT_UINT32 (buffer + 12);
8997 if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
8998 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
9002 /* we might allocate a bit too much, at least allocate 1 segment */
9003 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
9005 /* segments always start from 0 */
9010 for (i = 0; i < n_segments; i++) {
9013 gboolean time_valid = TRUE;
9014 QtDemuxSegment *segment;
9016 GstClockTime media_start = GST_CLOCK_TIME_NONE;
9019 media_time = QT_UINT64 (buffer + 8);
9020 duration = QT_UINT64 (buffer);
9021 if (media_time == G_MAXUINT64)
9024 media_time = QT_UINT32 (buffer + 4);
9025 duration = QT_UINT32 (buffer);
9026 if (media_time == G_MAXUINT32)
9031 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
9033 segment = &stream->segments[count++];
9035 /* time and duration expressed in global timescale */
9036 segment->time = stime;
9037 /* add non scaled values so we don't cause roundoff errors */
9038 if (duration || media_start == GST_CLOCK_TIME_NONE) {
9040 stime = QTTIME_TO_GSTTIME (qtdemux, time);
9041 segment->duration = stime - segment->time;
9043 /* zero duration does not imply media_start == media_stop
9044 * but, only specify media_start.*/
9045 stime = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
9046 if (GST_CLOCK_TIME_IS_VALID (stime) && time_valid
9047 && stime >= media_start) {
9048 segment->duration = stime - media_start;
9050 segment->duration = GST_CLOCK_TIME_NONE;
9053 segment->stop_time = stime;
9055 segment->trak_media_start = media_time;
9056 /* media_time expressed in stream timescale */
9058 segment->media_start = media_start;
9059 segment->media_stop = segment->media_start + segment->duration;
9060 media_segments_count++;
9062 segment->media_start = GST_CLOCK_TIME_NONE;
9063 segment->media_stop = GST_CLOCK_TIME_NONE;
9065 rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
9067 if (rate_int <= 1) {
9068 /* 0 is not allowed, some programs write 1 instead of the floating point
9070 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
9074 segment->rate = rate_int / 65536.0;
9077 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
9078 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
9079 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
9080 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
9081 i, GST_TIME_ARGS (segment->time),
9082 GST_TIME_ARGS (segment->duration),
9083 GST_TIME_ARGS (segment->media_start), media_time,
9084 GST_TIME_ARGS (segment->media_stop),
9085 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
9087 if (segment->stop_time > qtdemux->segment.stop) {
9088 GST_WARNING_OBJECT (qtdemux, "Segment %d "
9089 " extends to %" GST_TIME_FORMAT
9090 " past the end of the file duration %" GST_TIME_FORMAT
9091 " it will be truncated", i, GST_TIME_ARGS (segment->stop_time),
9092 GST_TIME_ARGS (qtdemux->segment.stop));
9093 qtdemux->segment.stop = segment->stop_time;
9096 buffer += entry_size;
9098 GST_DEBUG_OBJECT (qtdemux, "found %d segments", count);
9099 stream->n_segments = count;
9100 if (media_segments_count != 1)
9101 allow_pushbased_edts = FALSE;
9105 /* push based does not handle segments, so act accordingly here,
9106 * and warn if applicable */
9107 if (!qtdemux->pullbased && !allow_pushbased_edts) {
9108 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
9109 /* remove and use default one below, we stream like it anyway */
9110 g_free (stream->segments);
9111 stream->segments = NULL;
9112 stream->n_segments = 0;
9115 /* no segments, create one to play the complete trak */
9116 if (stream->n_segments == 0) {
9117 GstClockTime stream_duration =
9118 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
9120 if (stream->segments == NULL)
9121 stream->segments = g_new (QtDemuxSegment, 1);
9123 /* represent unknown our way */
9124 if (stream_duration == 0)
9125 stream_duration = GST_CLOCK_TIME_NONE;
9127 stream->segments[0].time = 0;
9128 stream->segments[0].stop_time = stream_duration;
9129 stream->segments[0].duration = stream_duration;
9130 stream->segments[0].media_start = 0;
9131 stream->segments[0].media_stop = stream_duration;
9132 stream->segments[0].rate = 1.0;
9133 stream->segments[0].trak_media_start = 0;
9135 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
9136 GST_TIME_ARGS (stream_duration));
9137 stream->n_segments = 1;
9138 stream->dummy_segment = TRUE;
9140 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
9146 * Parses the stsd atom of a svq3 trak looking for
9147 * the SMI and gama atoms.
9150 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
9151 const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
9153 const guint8 *_gamma = NULL;
9154 GstBuffer *_seqh = NULL;
9155 const guint8 *stsd_data = stsd_entry_data;
9156 guint32 length = QT_UINT32 (stsd_data);
9160 GST_WARNING_OBJECT (qtdemux, "stsd too short");
9166 version = QT_UINT16 (stsd_data);
9171 while (length > 8) {
9172 guint32 fourcc, size;
9174 size = QT_UINT32 (stsd_data);
9175 fourcc = QT_FOURCC (stsd_data + 4);
9176 data = stsd_data + 8;
9179 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
9180 "svq3 atom parsing");
9189 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
9190 " for gama atom, expected 12", size);
9195 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
9197 if (_seqh != NULL) {
9198 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
9199 " found, ignoring");
9201 seqh_size = QT_UINT32 (data + 4);
9202 if (seqh_size > 0) {
9203 _seqh = gst_buffer_new_and_alloc (seqh_size);
9204 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
9211 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
9212 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
9216 if (size <= length) {
9222 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
9225 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
9226 G_GUINT16_FORMAT, version);
9237 gst_buffer_unref (_seqh);
9242 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
9249 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
9250 * atom that might contain a 'data' atom with the rtsp uri.
9251 * This case was reported in bug #597497, some info about
9252 * the hndl atom can be found in TN1195
9254 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
9255 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
9258 guint32 dref_num_entries = 0;
9259 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
9260 gst_byte_reader_skip (&dref, 4) &&
9261 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
9264 /* search dref entries for hndl atom */
9265 for (i = 0; i < dref_num_entries; i++) {
9266 guint32 size = 0, type;
9267 guint8 string_len = 0;
9268 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
9269 qt_atom_parser_get_fourcc (&dref, &type)) {
9270 if (type == FOURCC_hndl) {
9271 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
9273 /* skip data reference handle bytes and the
9274 * following pascal string and some extra 4
9275 * bytes I have no idea what are */
9276 if (!gst_byte_reader_skip (&dref, 4) ||
9277 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
9278 !gst_byte_reader_skip (&dref, string_len + 4)) {
9279 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
9283 /* iterate over the atoms to find the data atom */
9284 while (gst_byte_reader_get_remaining (&dref) >= 8) {
9288 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
9289 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
9290 if (atom_type == FOURCC_data) {
9291 const guint8 *uri_aux = NULL;
9293 /* found the data atom that might contain the rtsp uri */
9294 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
9295 "hndl atom, interpreting it as an URI");
9296 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
9298 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
9299 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
9301 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
9302 "didn't contain a rtsp address");
9304 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
9309 /* skipping to the next entry */
9310 if (!gst_byte_reader_skip (&dref, atom_size - 8))
9313 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
9320 /* skip to the next entry */
9321 if (!gst_byte_reader_skip (&dref, size - 8))
9324 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
9327 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
9333 #define AMR_NB_ALL_MODES 0x81ff
9334 #define AMR_WB_ALL_MODES 0x83ff
9336 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
9338 /* The 'damr' atom is of the form:
9340 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
9341 * 32 b 8 b 16 b 8 b 8 b
9343 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
9344 * represents the highest mode used in the stream (and thus the maximum
9345 * bitrate), with a couple of special cases as seen below.
9348 /* Map of frame type ID -> bitrate */
9349 static const guint nb_bitrates[] = {
9350 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
9352 static const guint wb_bitrates[] = {
9353 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
9359 gst_buffer_map (buf, &map, GST_MAP_READ);
9361 if (map.size != 0x11) {
9362 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
9366 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
9367 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
9368 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
9372 mode_set = QT_UINT16 (map.data + 13);
9374 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
9375 max_mode = 7 + (wb ? 1 : 0);
9377 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
9378 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
9380 if (max_mode == -1) {
9381 GST_DEBUG ("No mode indication was found (mode set) = %x",
9386 gst_buffer_unmap (buf, &map);
9387 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
9390 gst_buffer_unmap (buf, &map);
9395 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
9396 GstByteReader * reader, guint32 * matrix, const gchar * atom)
9399 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
9405 if (gst_byte_reader_get_remaining (reader) < 36)
9408 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
9409 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
9410 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
9411 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
9412 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
9413 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
9414 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
9415 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
9416 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
9418 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
9419 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
9420 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
9422 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
9423 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
9425 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
9426 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
9433 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
9434 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
9441 * This macro will only compare value abdegh, it expects cfi to have already
9444 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
9445 (m)[3] == (d << 16) && (m)[4] == (e << 16))
9447 /* only handle the cases where the last column has standard values */
9448 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
9449 const gchar *rotation_tag = NULL;
9451 /* no rotation needed */
9452 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
9454 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
9455 rotation_tag = "rotate-90";
9456 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
9457 rotation_tag = "rotate-180";
9458 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
9459 rotation_tag = "rotate-270";
9461 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9464 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
9466 if (rotation_tag != NULL) {
9467 if (*taglist == NULL)
9468 *taglist = gst_tag_list_new_empty ();
9469 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
9470 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
9473 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9477 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
9478 * protected streams (sinf, frma, schm and schi); if the protection scheme is
9479 * Common Encryption (cenc), the function will also parse the tenc box (defined
9480 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
9481 * (typically an enc[v|a|t|s] sample entry); the function will set
9482 * @original_fmt to the fourcc of the original unencrypted stream format.
9483 * Returns TRUE if successful; FALSE otherwise. */
9485 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
9486 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
9493 g_return_val_if_fail (qtdemux != NULL, FALSE);
9494 g_return_val_if_fail (stream != NULL, FALSE);
9495 g_return_val_if_fail (container != NULL, FALSE);
9496 g_return_val_if_fail (original_fmt != NULL, FALSE);
9498 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
9499 if (G_UNLIKELY (!sinf)) {
9500 if (stream->protection_scheme_type == FOURCC_cenc) {
9501 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
9502 "mandatory for Common Encryption");
9508 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
9509 if (G_UNLIKELY (!frma)) {
9510 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
9514 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
9515 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
9516 GST_FOURCC_ARGS (*original_fmt));
9518 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
9520 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
9523 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
9524 stream->protection_scheme_version =
9525 QT_UINT32 ((const guint8 *) schm->data + 16);
9527 GST_DEBUG_OBJECT (qtdemux,
9528 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
9529 "protection_scheme_version: %#010x",
9530 GST_FOURCC_ARGS (stream->protection_scheme_type),
9531 stream->protection_scheme_version);
9533 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
9535 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
9538 if (stream->protection_scheme_type == FOURCC_cenc) {
9539 QtDemuxCencSampleSetInfo *info;
9541 const guint8 *tenc_data;
9542 guint32 isEncrypted;
9544 const guint8 *default_kid;
9547 if (G_UNLIKELY (!stream->protection_scheme_info))
9548 stream->protection_scheme_info =
9549 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
9551 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
9553 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
9555 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
9556 "which is mandatory for Common Encryption");
9559 tenc_data = (const guint8 *) tenc->data + 12;
9560 isEncrypted = QT_UINT24 (tenc_data);
9561 iv_size = QT_UINT8 (tenc_data + 3);
9562 default_kid = (tenc_data + 4);
9563 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
9564 gst_buffer_fill (kid_buf, 0, default_kid, 16);
9565 if (info->default_properties)
9566 gst_structure_free (info->default_properties);
9567 info->default_properties =
9568 gst_structure_new ("application/x-cenc",
9569 "iv_size", G_TYPE_UINT, iv_size,
9570 "encrypted", G_TYPE_BOOLEAN, (isEncrypted == 1),
9571 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
9572 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
9573 "is_encrypted=%u, iv_size=%u", isEncrypted, iv_size);
9574 gst_buffer_unref (kid_buf);
9580 * With each track we associate a new QtDemuxStream that contains all the info
9582 * traks that do not decode to something (like strm traks) will not have a pad.
9585 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
9606 QtDemuxStream *stream = NULL;
9607 gboolean new_stream = FALSE;
9608 gchar *codec = NULL;
9609 const guint8 *stsd_data;
9610 const guint8 *stsd_entry_data;
9611 guint remaining_stsd_len;
9612 guint stsd_entry_count;
9614 guint16 lang_code; /* quicktime lang code or packed iso code */
9616 guint32 tkhd_flags = 0;
9617 guint8 tkhd_version = 0;
9618 guint32 w = 0, h = 0;
9620 guint value_size, stsd_len, len;
9624 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
9626 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
9627 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
9628 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
9631 /* pick between 64 or 32 bits */
9632 value_size = tkhd_version == 1 ? 8 : 4;
9633 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
9634 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
9637 if (!qtdemux->got_moov) {
9638 if (qtdemux_find_stream (qtdemux, track_id))
9639 goto existing_stream;
9640 stream = _create_stream ();
9641 stream->track_id = track_id;
9644 stream = qtdemux_find_stream (qtdemux, track_id);
9646 GST_WARNING_OBJECT (qtdemux, "Stream not found, going to ignore it");
9650 /* reset reused stream */
9651 gst_qtdemux_stream_reset (qtdemux, stream);
9653 /* need defaults for fragments */
9654 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
9656 if ((tkhd_flags & 1) == 0)
9657 stream->disabled = TRUE;
9659 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
9660 tkhd_version, tkhd_flags, stream->track_id);
9662 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
9665 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
9666 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
9667 if (qtdemux->major_brand != FOURCC_mjp2 ||
9668 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
9672 len = QT_UINT32 ((guint8 *) mdhd->data);
9673 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
9674 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
9675 if (version == 0x01000000) {
9678 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
9679 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
9680 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
9684 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
9685 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
9686 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
9689 if (lang_code < 0x400) {
9690 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
9691 } else if (lang_code == 0x7fff) {
9692 stream->lang_id[0] = 0; /* unspecified */
9694 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
9695 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
9696 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
9697 stream->lang_id[3] = 0;
9700 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
9702 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
9704 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
9705 lang_code, stream->lang_id);
9707 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
9710 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
9711 /* chapters track reference */
9712 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
9714 gsize length = GST_READ_UINT32_BE (chap->data);
9715 if (qtdemux->chapters_track_id)
9716 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
9719 qtdemux->chapters_track_id =
9720 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
9725 /* fragmented files may have bogus duration in moov */
9726 if (!qtdemux->fragmented &&
9727 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
9728 guint64 tdur1, tdur2;
9730 /* don't overflow */
9731 tdur1 = stream->timescale * (guint64) qtdemux->duration;
9732 tdur2 = qtdemux->timescale * (guint64) stream->duration;
9735 * some of those trailers, nowadays, have prologue images that are
9736 * themselves video tracks as well. I haven't really found a way to
9737 * identify those yet, except for just looking at their duration. */
9738 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
9739 GST_WARNING_OBJECT (qtdemux,
9740 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
9741 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
9742 "found, assuming preview image or something; skipping track",
9743 stream->duration, stream->timescale, qtdemux->duration,
9744 qtdemux->timescale);
9746 gst_qtdemux_stream_free (qtdemux, stream);
9751 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
9754 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
9755 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
9757 len = QT_UINT32 ((guint8 *) hdlr->data);
9759 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
9760 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
9761 GST_FOURCC_ARGS (stream->subtype));
9763 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
9766 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
9769 /*parse svmi header if existing */
9770 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
9772 len = QT_UINT32 ((guint8 *) svmi->data);
9773 version = QT_UINT32 ((guint8 *) svmi->data + 8);
9775 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
9776 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
9777 guint8 frame_type, frame_layout;
9779 /* MPEG-A stereo video */
9780 if (qtdemux->major_brand == FOURCC_ss02)
9781 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
9783 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
9784 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
9785 switch (frame_type) {
9787 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
9790 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
9793 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
9796 /* mode 3 is primary/secondary view sequence, ie
9797 * left/right views in separate tracks. See section 7.2
9798 * of ISO/IEC 23000-11:2009 */
9799 GST_FIXME_OBJECT (qtdemux,
9800 "Implement stereo video in separate streams");
9803 if ((frame_layout & 0x1) == 0)
9804 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
9806 GST_LOG_OBJECT (qtdemux,
9807 "StereoVideo: composition type: %u, is_left_first: %u",
9808 frame_type, frame_layout);
9809 stream->multiview_mode = mode;
9810 stream->multiview_flags = flags;
9814 /* parse rest of tkhd */
9815 if (stream->subtype == FOURCC_vide) {
9818 /* version 1 uses some 64-bit ints */
9819 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
9822 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
9825 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
9826 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
9829 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
9830 &stream->stream_tags);
9834 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
9836 stsd_data = (const guint8 *) stsd->data;
9838 /* stsd should at least have one entry */
9839 stsd_len = QT_UINT32 (stsd_data);
9840 if (stsd_len < 24) {
9841 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
9842 if (stream->subtype == FOURCC_vivo) {
9844 gst_qtdemux_stream_free (qtdemux, stream);
9851 stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
9852 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
9853 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
9854 GST_LOG_OBJECT (qtdemux, "stsd entry count: %u", stsd_entry_count);
9856 stsd_entry_data = stsd_data + 16;
9857 remaining_stsd_len = stsd_len - 16;
9858 for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
9859 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
9861 /* and that entry should fit within stsd */
9862 len = QT_UINT32 (stsd_entry_data);
9863 if (len > remaining_stsd_len)
9866 entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
9867 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
9868 GST_FOURCC_ARGS (entry->fourcc));
9869 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
9871 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
9872 goto error_encrypted;
9874 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
9875 /* FIXME this looks wrong, there might be multiple children
9876 * with the same type */
9877 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
9878 stream->protected = TRUE;
9879 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
9880 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
9883 if (stream->subtype == FOURCC_vide) {
9885 gint depth, palette_size, palette_count;
9886 guint32 *palette_data = NULL;
9888 entry->sampled = TRUE;
9890 stream->display_width = w >> 16;
9891 stream->display_height = h >> 16;
9894 if (len < 86) /* TODO verify */
9897 entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
9898 entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
9899 entry->fps_n = 0; /* this is filled in later */
9900 entry->fps_d = 0; /* this is filled in later */
9901 entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
9902 entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
9904 /* if color_table_id is 0, ctab atom must follow; however some files
9905 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
9906 * if color table is not present we'll correct the value */
9907 if (entry->color_table_id == 0 &&
9909 || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
9910 entry->color_table_id = -1;
9913 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
9914 entry->width, entry->height, entry->bits_per_sample,
9915 entry->color_table_id);
9917 depth = entry->bits_per_sample;
9919 /* more than 32 bits means grayscale */
9920 gray = (depth > 32);
9921 /* low 32 bits specify the depth */
9924 /* different number of palette entries is determined by depth. */
9926 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
9927 palette_count = (1 << depth);
9928 palette_size = palette_count * 4;
9930 if (entry->color_table_id) {
9931 switch (palette_count) {
9935 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
9938 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
9943 g_memdup (ff_qt_grayscale_palette_16, palette_size);
9945 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
9950 g_memdup (ff_qt_grayscale_palette_256, palette_size);
9952 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
9955 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
9956 (_("The video in this file might not play correctly.")),
9957 ("unsupported palette depth %d", depth));
9961 gint i, j, start, end;
9967 start = QT_UINT32 (stsd_entry_data + offset + 70);
9968 palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
9969 end = QT_UINT16 (stsd_entry_data + offset + 76);
9971 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
9972 start, end, palette_count);
9979 if (len < 94 + (end - start) * 8)
9982 /* palette is always the same size */
9983 palette_data = g_malloc0 (256 * 4);
9984 palette_size = 256 * 4;
9986 for (j = 0, i = start; i <= end; j++, i++) {
9989 a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
9990 r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
9991 g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
9992 b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
9994 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
9995 (g & 0xff00) | (b >> 8);
10000 gst_caps_unref (entry->caps);
10003 qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
10005 if (G_UNLIKELY (!entry->caps)) {
10006 g_free (palette_data);
10007 goto unknown_stream;
10011 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
10012 GST_TAG_VIDEO_CODEC, codec, NULL);
10017 if (palette_data) {
10020 if (entry->rgb8_palette)
10021 gst_memory_unref (entry->rgb8_palette);
10022 entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
10023 palette_data, palette_size, 0, palette_size, palette_data, g_free);
10025 s = gst_caps_get_structure (entry->caps, 0);
10027 /* non-raw video has a palette_data property. raw video has the palette as
10028 * an extra plane that we append to the output buffers before we push
10030 if (!gst_structure_has_name (s, "video/x-raw")) {
10031 GstBuffer *palette;
10033 palette = gst_buffer_new ();
10034 gst_buffer_append_memory (palette, entry->rgb8_palette);
10035 entry->rgb8_palette = NULL;
10037 gst_caps_set_simple (entry->caps, "palette_data",
10038 GST_TYPE_BUFFER, palette, NULL);
10039 gst_buffer_unref (palette);
10041 } else if (palette_count != 0) {
10042 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
10043 (NULL), ("Unsupported palette depth %d", depth));
10046 GST_LOG_OBJECT (qtdemux, "frame count: %u",
10047 QT_UINT16 (stsd_entry_data + offset + 32));
10053 /* pick 'the' stsd child */
10054 mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10055 if (!stream->protected) {
10056 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
10060 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) {
10066 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
10067 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
10068 colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
10069 fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
10073 const guint8 *pasp_data = (const guint8 *) pasp->data;
10074 gint len = QT_UINT32 (pasp_data);
10077 CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
10078 CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
10080 CUR_STREAM (stream)->par_w = 0;
10081 CUR_STREAM (stream)->par_h = 0;
10084 CUR_STREAM (stream)->par_w = 0;
10085 CUR_STREAM (stream)->par_h = 0;
10089 const guint8 *fiel_data = (const guint8 *) fiel->data;
10090 gint len = QT_UINT32 (fiel_data);
10093 CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
10094 CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
10099 const guint8 *colr_data = (const guint8 *) colr->data;
10100 gint len = QT_UINT32 (colr_data);
10102 if (len == 19 || len == 18) {
10103 guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
10105 if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
10106 guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
10107 guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
10108 guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
10109 gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
10111 switch (primaries) {
10113 CUR_STREAM (stream)->colorimetry.primaries =
10114 GST_VIDEO_COLOR_PRIMARIES_BT709;
10117 CUR_STREAM (stream)->colorimetry.primaries =
10118 GST_VIDEO_COLOR_PRIMARIES_BT470BG;
10121 CUR_STREAM (stream)->colorimetry.primaries =
10122 GST_VIDEO_COLOR_PRIMARIES_SMPTE170M;
10125 CUR_STREAM (stream)->colorimetry.primaries =
10126 GST_VIDEO_COLOR_PRIMARIES_BT2020;
10132 switch (transfer_function) {
10134 CUR_STREAM (stream)->colorimetry.transfer =
10135 GST_VIDEO_TRANSFER_BT709;
10138 CUR_STREAM (stream)->colorimetry.transfer =
10139 GST_VIDEO_TRANSFER_SMPTE240M;
10147 CUR_STREAM (stream)->colorimetry.matrix =
10148 GST_VIDEO_COLOR_MATRIX_BT709;
10151 CUR_STREAM (stream)->colorimetry.matrix =
10152 GST_VIDEO_COLOR_MATRIX_BT601;
10155 CUR_STREAM (stream)->colorimetry.matrix =
10156 GST_VIDEO_COLOR_MATRIX_SMPTE240M;
10159 CUR_STREAM (stream)->colorimetry.matrix =
10160 GST_VIDEO_COLOR_MATRIX_BT2020;
10166 CUR_STREAM (stream)->colorimetry.range =
10167 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
10168 GST_VIDEO_COLOR_RANGE_16_235;
10170 GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
10173 GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
10178 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
10179 stream->stream_tags);
10186 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10187 const guint8 *avc_data = stsd_entry_data + 0x56;
10190 while (len >= 0x8) {
10193 if (QT_UINT32 (avc_data) <= len)
10194 size = QT_UINT32 (avc_data) - 0x8;
10199 /* No real data, so break out */
10202 switch (QT_FOURCC (avc_data + 0x4)) {
10205 /* parse, if found */
10208 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
10210 /* First 4 bytes are the length of the atom, the next 4 bytes
10211 * are the fourcc, the next 1 byte is the version, and the
10212 * subsequent bytes are profile_tier_level structure like data. */
10213 gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
10214 avc_data + 8 + 1, size - 1);
10215 buf = gst_buffer_new_and_alloc (size);
10216 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
10217 gst_caps_set_simple (entry->caps,
10218 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10219 gst_buffer_unref (buf);
10227 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
10229 /* First 4 bytes are the length of the atom, the next 4 bytes
10230 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
10231 * next 1 byte is the version, and the
10232 * subsequent bytes are sequence parameter set like data. */
10234 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
10236 gst_codec_utils_h264_caps_set_level_and_profile
10237 (entry->caps, avc_data + 8 + 40 + 1, size - 1);
10239 buf = gst_buffer_new_and_alloc (size);
10240 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
10241 gst_caps_set_simple (entry->caps,
10242 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10243 gst_buffer_unref (buf);
10249 guint avg_bitrate, max_bitrate;
10251 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
10255 max_bitrate = QT_UINT32 (avc_data + 0xc);
10256 avg_bitrate = QT_UINT32 (avc_data + 0x10);
10258 if (!max_bitrate && !avg_bitrate)
10261 /* Some muxers seem to swap the average and maximum bitrates
10262 * (I'm looking at you, YouTube), so we swap for sanity. */
10263 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
10264 guint temp = avg_bitrate;
10266 avg_bitrate = max_bitrate;
10267 max_bitrate = temp;
10270 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
10271 gst_tag_list_add (stream->stream_tags,
10272 GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
10273 max_bitrate, NULL);
10275 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
10276 gst_tag_list_add (stream->stream_tags,
10277 GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
10289 avc_data += size + 8;
10298 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10299 const guint8 *hevc_data = stsd_entry_data + 0x56;
10302 while (len >= 0x8) {
10305 if (QT_UINT32 (hevc_data) <= len)
10306 size = QT_UINT32 (hevc_data) - 0x8;
10311 /* No real data, so break out */
10314 switch (QT_FOURCC (hevc_data + 0x4)) {
10317 /* parse, if found */
10320 GST_DEBUG_OBJECT (qtdemux, "found hvcC codec_data in stsd");
10322 /* First 4 bytes are the length of the atom, the next 4 bytes
10323 * are the fourcc, the next 1 byte is the version, and the
10324 * subsequent bytes are sequence parameter set like data. */
10325 gst_codec_utils_h265_caps_set_level_tier_and_profile
10326 (entry->caps, hevc_data + 8 + 1, size - 1);
10328 buf = gst_buffer_new_and_alloc (size);
10329 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
10330 gst_caps_set_simple (entry->caps,
10331 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10332 gst_buffer_unref (buf);
10339 hevc_data += size + 8;
10352 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
10353 GST_FOURCC_ARGS (fourcc));
10355 /* codec data might be in glbl extension atom */
10357 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
10363 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
10365 len = QT_UINT32 (data);
10368 buf = gst_buffer_new_and_alloc (len);
10369 gst_buffer_fill (buf, 0, data + 8, len);
10370 gst_caps_set_simple (entry->caps,
10371 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10372 gst_buffer_unref (buf);
10379 /* see annex I of the jpeg2000 spec */
10380 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
10381 const guint8 *data;
10382 const gchar *colorspace = NULL;
10384 guint32 ncomp_map = 0;
10385 gint32 *comp_map = NULL;
10386 guint32 nchan_def = 0;
10387 gint32 *chan_def = NULL;
10389 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
10390 /* some required atoms */
10391 mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10394 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
10398 /* number of components; redundant with info in codestream, but useful
10400 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
10401 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
10403 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
10405 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
10408 GST_DEBUG_OBJECT (qtdemux, "found colr");
10409 /* extract colour space info */
10410 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
10411 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
10413 colorspace = "sRGB";
10416 colorspace = "GRAY";
10419 colorspace = "sYUV";
10427 /* colr is required, and only values 16, 17, and 18 are specified,
10428 so error if we have no colorspace */
10431 /* extract component mapping */
10432 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
10434 guint32 cmap_len = 0;
10436 cmap_len = QT_UINT32 (cmap->data);
10437 if (cmap_len >= 8) {
10438 /* normal box, subtract off header */
10440 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
10441 if (cmap_len % 4 == 0) {
10442 ncomp_map = (cmap_len / 4);
10443 comp_map = g_new0 (gint32, ncomp_map);
10444 for (i = 0; i < ncomp_map; i++) {
10447 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
10448 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
10449 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
10450 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
10455 /* extract channel definitions */
10456 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
10458 guint32 cdef_len = 0;
10460 cdef_len = QT_UINT32 (cdef->data);
10461 if (cdef_len >= 10) {
10462 /* normal box, subtract off header and len */
10464 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
10465 if (cdef_len % 6 == 0) {
10466 nchan_def = (cdef_len / 6);
10467 chan_def = g_new0 (gint32, nchan_def);
10468 for (i = 0; i < nchan_def; i++)
10470 for (i = 0; i < nchan_def; i++) {
10471 guint16 cn, typ, asoc;
10472 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
10473 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
10474 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
10475 if (cn < nchan_def) {
10478 chan_def[cn] = asoc;
10481 chan_def[cn] = 0; /* alpha */
10484 chan_def[cn] = -typ;
10492 gst_caps_set_simple (entry->caps,
10493 "num-components", G_TYPE_INT, ncomp, NULL);
10494 gst_caps_set_simple (entry->caps,
10495 "colorspace", G_TYPE_STRING, colorspace, NULL);
10498 GValue arr = { 0, };
10499 GValue elt = { 0, };
10501 g_value_init (&arr, GST_TYPE_ARRAY);
10502 g_value_init (&elt, G_TYPE_INT);
10503 for (i = 0; i < ncomp_map; i++) {
10504 g_value_set_int (&elt, comp_map[i]);
10505 gst_value_array_append_value (&arr, &elt);
10507 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
10508 "component-map", &arr);
10509 g_value_unset (&elt);
10510 g_value_unset (&arr);
10515 GValue arr = { 0, };
10516 GValue elt = { 0, };
10518 g_value_init (&arr, GST_TYPE_ARRAY);
10519 g_value_init (&elt, G_TYPE_INT);
10520 for (i = 0; i < nchan_def; i++) {
10521 g_value_set_int (&elt, chan_def[i]);
10522 gst_value_array_append_value (&arr, &elt);
10524 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
10525 "channel-definitions", &arr);
10526 g_value_unset (&elt);
10527 g_value_unset (&arr);
10531 /* some optional atoms */
10532 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
10533 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
10535 /* indicate possible fields in caps */
10537 data = (guint8 *) field->data + 8;
10539 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
10540 (gint) * data, NULL);
10542 /* add codec_data if provided */
10547 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
10548 data = prefix->data;
10549 len = QT_UINT32 (data);
10552 buf = gst_buffer_new_and_alloc (len);
10553 gst_buffer_fill (buf, 0, data + 8, len);
10554 gst_caps_set_simple (entry->caps,
10555 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10556 gst_buffer_unref (buf);
10565 GstBuffer *seqh = NULL;
10566 const guint8 *gamma_data = NULL;
10567 gint len = QT_UINT32 (stsd_data); /* FIXME review - why put the whole stsd in codec data? */
10569 qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
10572 gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
10573 QT_FP32 (gamma_data), NULL);
10576 /* sorry for the bad name, but we don't know what this is, other
10577 * than its own fourcc */
10578 gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
10580 gst_buffer_unref (seqh);
10583 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
10584 buf = gst_buffer_new_and_alloc (len);
10585 gst_buffer_fill (buf, 0, stsd_data, len);
10586 gst_caps_set_simple (entry->caps,
10587 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10588 gst_buffer_unref (buf);
10593 /* https://developer.apple.com/standards/qtff-2001.pdf,
10594 * page 92, "Video Sample Description", under table 3.1 */
10597 const gint compressor_offset =
10598 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
10599 const gint min_size = compressor_offset + 32 + 2 + 2;
10602 guint16 color_table_id = 0;
10605 GST_DEBUG_OBJECT (qtdemux, "found jpeg");
10607 /* recover information on interlaced/progressive */
10608 jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
10612 len = QT_UINT32 (jpeg->data);
10613 GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
10615 if (len >= min_size) {
10616 gst_byte_reader_init (&br, jpeg->data, len);
10618 gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
10619 gst_byte_reader_get_uint16_le (&br, &color_table_id);
10620 if (color_table_id != 0) {
10621 /* the spec says there can be concatenated chunks in the data, and we want
10622 * to find one called field. Walk through them. */
10623 gint offset = min_size;
10624 while (offset + 8 < len) {
10625 guint32 size = 0, tag;
10626 ok = gst_byte_reader_get_uint32_le (&br, &size);
10627 ok &= gst_byte_reader_get_uint32_le (&br, &tag);
10628 if (!ok || size < 8) {
10629 GST_WARNING_OBJECT (qtdemux,
10630 "Failed to walk optional chunk list");
10633 GST_DEBUG_OBJECT (qtdemux,
10634 "Found optional %4.4s chunk, size %u",
10635 (const char *) &tag, size);
10636 if (tag == FOURCC_fiel) {
10637 guint8 n_fields = 0, ordering = 0;
10638 gst_byte_reader_get_uint8 (&br, &n_fields);
10639 gst_byte_reader_get_uint8 (&br, &ordering);
10640 if (n_fields == 1 || n_fields == 2) {
10641 GST_DEBUG_OBJECT (qtdemux,
10642 "Found fiel tag with %u fields, ordering %u",
10643 n_fields, ordering);
10645 gst_caps_set_simple (CUR_STREAM (stream)->caps,
10646 "interlace-mode", G_TYPE_STRING, "interleaved",
10649 GST_WARNING_OBJECT (qtdemux,
10650 "Found fiel tag with invalid fields (%u)", n_fields);
10656 GST_DEBUG_OBJECT (qtdemux,
10657 "Color table ID is 0, not trying to get interlacedness");
10660 GST_WARNING_OBJECT (qtdemux,
10661 "Length of jpeg chunk is too small, not trying to get interlacedness");
10669 gst_caps_set_simple (entry->caps,
10670 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 66),
10676 GNode *xith, *xdxt;
10678 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
10679 xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10683 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
10687 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
10688 /* collect the headers and store them in a stream list so that we can
10689 * send them out first */
10690 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
10700 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
10701 ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10704 ovc1_data = ovc1->data;
10705 ovc1_len = QT_UINT32 (ovc1_data);
10706 if (ovc1_len <= 198) {
10707 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
10710 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
10711 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
10712 gst_caps_set_simple (entry->caps,
10713 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10714 gst_buffer_unref (buf);
10719 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10720 const guint8 *vc1_data = stsd_entry_data + 0x56;
10726 if (QT_UINT32 (vc1_data) <= len)
10727 size = QT_UINT32 (vc1_data) - 8;
10732 /* No real data, so break out */
10735 switch (QT_FOURCC (vc1_data + 0x4)) {
10736 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
10740 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
10741 buf = gst_buffer_new_and_alloc (size);
10742 gst_buffer_fill (buf, 0, vc1_data + 8, size);
10743 gst_caps_set_simple (entry->caps,
10744 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10745 gst_buffer_unref (buf);
10752 vc1_data += size + 8;
10761 GST_INFO_OBJECT (qtdemux,
10762 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10763 GST_FOURCC_ARGS (fourcc), entry->caps);
10765 } else if (stream->subtype == FOURCC_soun) {
10766 int version, samplesize;
10767 guint16 compression_id;
10768 gboolean amrwb = FALSE;
10771 /* sample description entry (16) + sound sample description v0 (20) */
10775 version = QT_UINT32 (stsd_entry_data + offset);
10776 entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
10777 samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
10778 compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
10779 entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
10781 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
10782 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
10783 QT_UINT32 (stsd_entry_data + offset + 4));
10784 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
10785 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
10786 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
10787 GST_LOG_OBJECT (qtdemux, "packet size: %d",
10788 QT_UINT16 (stsd_entry_data + offset + 14));
10789 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
10791 if (compression_id == 0xfffe)
10792 entry->sampled = TRUE;
10794 /* first assume uncompressed audio */
10795 entry->bytes_per_sample = samplesize / 8;
10796 entry->samples_per_frame = entry->n_channels;
10797 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
10798 entry->samples_per_packet = entry->samples_per_frame;
10799 entry->bytes_per_packet = entry->bytes_per_sample;
10803 /* Yes, these have to be hard-coded */
10806 entry->samples_per_packet = 6;
10807 entry->bytes_per_packet = 1;
10808 entry->bytes_per_frame = 1 * entry->n_channels;
10809 entry->bytes_per_sample = 1;
10810 entry->samples_per_frame = 6 * entry->n_channels;
10815 entry->samples_per_packet = 3;
10816 entry->bytes_per_packet = 1;
10817 entry->bytes_per_frame = 1 * entry->n_channels;
10818 entry->bytes_per_sample = 1;
10819 entry->samples_per_frame = 3 * entry->n_channels;
10824 entry->samples_per_packet = 64;
10825 entry->bytes_per_packet = 34;
10826 entry->bytes_per_frame = 34 * entry->n_channels;
10827 entry->bytes_per_sample = 2;
10828 entry->samples_per_frame = 64 * entry->n_channels;
10834 entry->samples_per_packet = 1;
10835 entry->bytes_per_packet = 1;
10836 entry->bytes_per_frame = 1 * entry->n_channels;
10837 entry->bytes_per_sample = 1;
10838 entry->samples_per_frame = 1 * entry->n_channels;
10843 entry->samples_per_packet = 160;
10844 entry->bytes_per_packet = 33;
10845 entry->bytes_per_frame = 33 * entry->n_channels;
10846 entry->bytes_per_sample = 2;
10847 entry->samples_per_frame = 160 * entry->n_channels;
10854 if (version == 0x00010000) {
10855 /* sample description entry (16) + sound sample description v1 (20+16) */
10867 /* only parse extra decoding config for non-pcm audio */
10868 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
10869 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
10870 entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
10871 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
10873 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
10874 entry->samples_per_packet);
10875 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
10876 entry->bytes_per_packet);
10877 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
10878 entry->bytes_per_frame);
10879 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
10880 entry->bytes_per_sample);
10882 if (!entry->sampled && entry->bytes_per_packet) {
10883 entry->samples_per_frame = (entry->bytes_per_frame /
10884 entry->bytes_per_packet) * entry->samples_per_packet;
10885 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
10886 entry->samples_per_frame);
10891 } else if (version == 0x00020000) {
10898 /* sample description entry (16) + sound sample description v2 (56) */
10902 qtfp.val = QT_UINT64 (stsd_entry_data + offset + 4);
10903 entry->rate = qtfp.fp;
10904 entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
10906 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
10907 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
10908 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
10909 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
10910 QT_UINT32 (stsd_entry_data + offset + 20));
10911 GST_LOG_OBJECT (qtdemux, "format flags: %X",
10912 QT_UINT32 (stsd_entry_data + offset + 24));
10913 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
10914 QT_UINT32 (stsd_entry_data + offset + 28));
10915 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
10916 QT_UINT32 (stsd_entry_data + offset + 32));
10917 } else if (version != 0x00000) {
10918 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
10923 gst_caps_unref (entry->caps);
10925 entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
10926 stsd_entry_data + 32, len - 16, &codec);
10934 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
10936 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
10938 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
10940 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
10943 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
10944 gst_caps_set_simple (entry->caps,
10945 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE",
10952 const guint8 *owma_data;
10953 const gchar *codec_name = NULL;
10957 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
10958 /* FIXME this should also be gst_riff_strf_auds,
10959 * but the latter one is actually missing bits-per-sample :( */
10964 gint32 nSamplesPerSec;
10965 gint32 nAvgBytesPerSec;
10966 gint16 nBlockAlign;
10967 gint16 wBitsPerSample;
10970 WAVEFORMATEX *wfex;
10972 GST_DEBUG_OBJECT (qtdemux, "parse owma");
10973 owma_data = stsd_entry_data;
10974 owma_len = QT_UINT32 (owma_data);
10975 if (owma_len <= 54) {
10976 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
10979 wfex = (WAVEFORMATEX *) (owma_data + 36);
10980 buf = gst_buffer_new_and_alloc (owma_len - 54);
10981 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
10982 if (wfex->wFormatTag == 0x0161) {
10983 codec_name = "Windows Media Audio";
10985 } else if (wfex->wFormatTag == 0x0162) {
10986 codec_name = "Windows Media Audio 9 Pro";
10988 } else if (wfex->wFormatTag == 0x0163) {
10989 codec_name = "Windows Media Audio 9 Lossless";
10990 /* is that correct? gstffmpegcodecmap.c is missing it, but
10991 * fluendo codec seems to support it */
10995 gst_caps_set_simple (entry->caps,
10996 "codec_data", GST_TYPE_BUFFER, buf,
10997 "wmaversion", G_TYPE_INT, version,
10998 "block_align", G_TYPE_INT,
10999 GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
11000 GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
11001 GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
11002 GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
11003 gst_buffer_unref (buf);
11007 codec = g_strdup (codec_name);
11013 gint len = QT_UINT32 (stsd_entry_data) - offset;
11014 const guint8 *wfex_data = stsd_entry_data + offset;
11015 const gchar *codec_name = NULL;
11017 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
11018 /* FIXME this should also be gst_riff_strf_auds,
11019 * but the latter one is actually missing bits-per-sample :( */
11024 gint32 nSamplesPerSec;
11025 gint32 nAvgBytesPerSec;
11026 gint16 nBlockAlign;
11027 gint16 wBitsPerSample;
11032 /* FIXME: unify with similar wavformatex parsing code above */
11033 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
11039 if (QT_UINT32 (wfex_data) <= len)
11040 size = QT_UINT32 (wfex_data) - 8;
11045 /* No real data, so break out */
11048 switch (QT_FOURCC (wfex_data + 4)) {
11049 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
11051 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
11056 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
11057 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
11058 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
11059 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
11060 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
11061 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
11062 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
11064 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
11065 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
11066 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
11067 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
11068 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
11069 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
11071 if (wfex.wFormatTag == 0x0161) {
11072 codec_name = "Windows Media Audio";
11074 } else if (wfex.wFormatTag == 0x0162) {
11075 codec_name = "Windows Media Audio 9 Pro";
11077 } else if (wfex.wFormatTag == 0x0163) {
11078 codec_name = "Windows Media Audio 9 Lossless";
11079 /* is that correct? gstffmpegcodecmap.c is missing it, but
11080 * fluendo codec seems to support it */
11084 gst_caps_set_simple (entry->caps,
11085 "wmaversion", G_TYPE_INT, version,
11086 "block_align", G_TYPE_INT, wfex.nBlockAlign,
11087 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
11088 "width", G_TYPE_INT, wfex.wBitsPerSample,
11089 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
11091 if (size > wfex.cbSize) {
11094 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
11095 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
11096 size - wfex.cbSize);
11097 gst_caps_set_simple (entry->caps,
11098 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11099 gst_buffer_unref (buf);
11101 GST_WARNING_OBJECT (qtdemux, "no codec data");
11106 codec = g_strdup (codec_name);
11114 wfex_data += size + 8;
11120 const guint8 *opus_data;
11121 guint8 *channel_mapping = NULL;
11124 guint8 channel_mapping_family;
11125 guint8 stream_count;
11126 guint8 coupled_count;
11129 opus_data = stsd_entry_data;
11131 channels = GST_READ_UINT8 (opus_data + 45);
11132 rate = GST_READ_UINT32_LE (opus_data + 48);
11133 channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
11134 stream_count = GST_READ_UINT8 (opus_data + 55);
11135 coupled_count = GST_READ_UINT8 (opus_data + 56);
11137 if (channels > 0) {
11138 channel_mapping = g_malloc (channels * sizeof (guint8));
11139 for (i = 0; i < channels; i++)
11140 channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
11143 entry->caps = gst_codec_utils_opus_create_caps (rate, channels,
11144 channel_mapping_family, stream_count, coupled_count,
11156 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11157 GST_TAG_AUDIO_CODEC, codec, NULL);
11161 /* some bitrate info may have ended up in caps */
11162 s = gst_caps_get_structure (entry->caps, 0);
11163 gst_structure_get_int (s, "bitrate", &bitrate);
11165 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11166 GST_TAG_BITRATE, bitrate, NULL);
11169 mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11170 if (!stream->protected) {
11172 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) {
11176 if (stream->protected && fourcc == FOURCC_mp4a) {
11177 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) {
11181 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_mp4a) {
11189 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
11191 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
11193 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
11197 /* If the fourcc's bottom 16 bits gives 'sm', then the top
11198 16 bits is a byte-swapped wave-style codec identifier,
11199 and we can find a WAVE header internally to a 'wave' atom here.
11200 This can more clearly be thought of as 'ms' as the top 16 bits, and a
11201 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
11204 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
11205 if (len < offset + 20) {
11206 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
11208 guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
11209 const guint8 *data = stsd_entry_data + offset + 16;
11211 GNode *waveheadernode;
11213 wavenode = g_node_new ((guint8 *) data);
11214 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
11215 const guint8 *waveheader;
11218 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
11219 if (waveheadernode) {
11220 waveheader = (const guint8 *) waveheadernode->data;
11221 headerlen = QT_UINT32 (waveheader);
11223 if (headerlen > 8) {
11224 gst_riff_strf_auds *header = NULL;
11225 GstBuffer *headerbuf;
11231 headerbuf = gst_buffer_new_and_alloc (headerlen);
11232 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
11234 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
11235 headerbuf, &header, &extra)) {
11236 gst_caps_unref (entry->caps);
11237 /* FIXME: Need to do something with the channel reorder map */
11239 gst_riff_create_audio_caps (header->format, NULL, header,
11240 extra, NULL, NULL, NULL);
11243 gst_buffer_unref (extra);
11248 GST_DEBUG ("Didn't find waveheadernode for this codec");
11250 g_node_destroy (wavenode);
11253 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11254 stream->stream_tags);
11258 /* FIXME: what is in the chunk? */
11261 gint len = QT_UINT32 (stsd_data);
11263 /* seems to be always = 116 = 0x74 */
11269 gint len = QT_UINT32 (stsd_entry_data);
11272 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
11274 gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
11275 gst_caps_set_simple (entry->caps,
11276 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11277 gst_buffer_unref (buf);
11279 gst_caps_set_simple (entry->caps,
11280 "samplesize", G_TYPE_INT, samplesize, NULL);
11285 GNode *alac, *wave = NULL;
11287 /* apparently, m4a has this atom appended directly in the stsd entry,
11288 * while mov has it in a wave atom */
11289 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
11291 /* alac now refers to stsd entry atom */
11292 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
11294 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
11296 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
11299 const guint8 *alac_data = alac->data;
11300 gint len = QT_UINT32 (alac->data);
11304 GST_DEBUG_OBJECT (qtdemux,
11305 "discarding alac atom with unexpected len %d", len);
11307 /* codec-data contains alac atom size and prefix,
11308 * ffmpeg likes it that way, not quite gst-ish though ...*/
11309 buf = gst_buffer_new_and_alloc (len);
11310 gst_buffer_fill (buf, 0, alac->data, len);
11311 gst_caps_set_simple (entry->caps,
11312 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11313 gst_buffer_unref (buf);
11315 entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
11316 entry->n_channels = QT_UINT8 (alac_data + 21);
11317 entry->rate = QT_UINT32 (alac_data + 32);
11320 gst_caps_set_simple (entry->caps,
11321 "samplesize", G_TYPE_INT, samplesize, NULL);
11326 /* The codingname of the sample entry is 'fLaC' */
11327 GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
11330 /* The 'dfLa' box is added to the sample entry to convey
11331 initializing information for the decoder. */
11332 const GNode *dfla =
11333 qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
11336 const guint32 len = QT_UINT32 (dfla->data);
11338 /* Must contain at least dfLa box header (12),
11339 * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
11341 GST_DEBUG_OBJECT (qtdemux,
11342 "discarding dfla atom with unexpected len %d", len);
11344 /* skip dfLa header to get the METADATA_BLOCKs */
11345 const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
11346 const guint32 metadata_blocks_len = len - 12;
11348 gchar *stream_marker = g_strdup ("fLaC");
11349 GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
11350 strlen (stream_marker));
11353 guint32 remainder = 0;
11354 guint32 block_size = 0;
11355 gboolean is_last = FALSE;
11357 GValue array = G_VALUE_INIT;
11358 GValue value = G_VALUE_INIT;
11360 g_value_init (&array, GST_TYPE_ARRAY);
11361 g_value_init (&value, GST_TYPE_BUFFER);
11363 gst_value_set_buffer (&value, block);
11364 gst_value_array_append_value (&array, &value);
11365 g_value_reset (&value);
11367 gst_buffer_unref (block);
11369 /* check there's at least one METADATA_BLOCK_HEADER's worth
11370 * of data, and we haven't already finished parsing */
11371 while (!is_last && ((index + 3) < metadata_blocks_len)) {
11372 remainder = metadata_blocks_len - index;
11374 /* add the METADATA_BLOCK_HEADER size to the signalled size */
11376 (metadata_blocks[index + 1] << 16) +
11377 (metadata_blocks[index + 2] << 8) +
11378 metadata_blocks[index + 3];
11380 /* be careful not to read off end of box */
11381 if (block_size > remainder) {
11385 is_last = metadata_blocks[index] >> 7;
11387 block = gst_buffer_new_and_alloc (block_size);
11389 gst_buffer_fill (block, 0, &metadata_blocks[index],
11392 gst_value_set_buffer (&value, block);
11393 gst_value_array_append_value (&array, &value);
11394 g_value_reset (&value);
11396 gst_buffer_unref (block);
11398 index += block_size;
11401 /* only append the metadata if we successfully read all of it */
11403 gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
11404 (stream)->caps, 0), "streamheader", &array);
11406 GST_WARNING_OBJECT (qtdemux,
11407 "discarding all METADATA_BLOCKs due to invalid "
11408 "block_size %d at idx %d, rem %d", block_size, index,
11412 g_value_unset (&value);
11413 g_value_unset (&array);
11415 /* The sample rate obtained from the stsd may not be accurate
11416 * since it cannot represent rates greater than 65535Hz, so
11417 * override that value with the sample rate from the
11418 * METADATA_BLOCK_STREAMINFO block */
11419 CUR_STREAM (stream)->rate =
11420 (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
11431 gint len = QT_UINT32 (stsd_entry_data);
11434 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
11437 gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
11439 /* If we have enough data, let's try to get the 'damr' atom. See
11440 * the 3GPP container spec (26.244) for more details. */
11441 if ((len - 0x34) > 8 &&
11442 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
11443 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11444 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
11447 gst_caps_set_simple (entry->caps,
11448 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11449 gst_buffer_unref (buf);
11455 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
11456 gint len = QT_UINT32 (stsd_entry_data);
11459 guint16 sound_version = QT_UINT16 (stsd_entry_data + 16);
11461 if (sound_version == 1) {
11462 guint16 channels = QT_UINT16 (stsd_entry_data + 24);
11463 guint32 time_scale = QT_UINT32 (stsd_entry_data + 30);
11464 guint8 codec_data[2];
11466 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
11468 gint sample_rate_index =
11469 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
11471 /* build AAC codec data */
11472 codec_data[0] = profile << 3;
11473 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
11474 codec_data[1] = (sample_rate_index & 0x01) << 7;
11475 codec_data[1] |= (channels & 0xF) << 3;
11477 buf = gst_buffer_new_and_alloc (2);
11478 gst_buffer_fill (buf, 0, codec_data, 2);
11479 gst_caps_set_simple (entry->caps,
11480 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11481 gst_buffer_unref (buf);
11487 /* Fully handled elsewhere */
11490 GST_INFO_OBJECT (qtdemux,
11491 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11495 GST_INFO_OBJECT (qtdemux,
11496 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11497 GST_FOURCC_ARGS (fourcc), entry->caps);
11499 } else if (stream->subtype == FOURCC_strm) {
11500 if (fourcc == FOURCC_rtsp) {
11501 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
11503 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
11504 GST_FOURCC_ARGS (fourcc));
11505 goto unknown_stream;
11507 entry->sampled = TRUE;
11508 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
11509 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
11511 entry->sampled = TRUE;
11512 entry->sparse = TRUE;
11515 qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11518 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11519 GST_TAG_SUBTITLE_CODEC, codec, NULL);
11524 /* hunt for sort-of codec data */
11528 GNode *mp4s = NULL;
11529 GNode *esds = NULL;
11531 /* look for palette in a stsd->mp4s->esds sub-atom */
11532 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
11534 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
11535 if (esds == NULL) {
11537 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
11541 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11542 stream->stream_tags);
11546 GST_INFO_OBJECT (qtdemux,
11547 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11550 GST_INFO_OBJECT (qtdemux,
11551 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11552 GST_FOURCC_ARGS (fourcc), entry->caps);
11554 /* everything in 1 sample */
11555 entry->sampled = TRUE;
11558 qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11561 if (entry->caps == NULL)
11562 goto unknown_stream;
11565 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11566 GST_TAG_SUBTITLE_CODEC, codec, NULL);
11572 /* promote to sampled format */
11573 if (entry->fourcc == FOURCC_samr) {
11574 /* force mono 8000 Hz for AMR */
11575 entry->sampled = TRUE;
11576 entry->n_channels = 1;
11577 entry->rate = 8000;
11578 } else if (entry->fourcc == FOURCC_sawb) {
11579 /* force mono 16000 Hz for AMR-WB */
11580 entry->sampled = TRUE;
11581 entry->n_channels = 1;
11582 entry->rate = 16000;
11583 } else if (entry->fourcc == FOURCC_mp4a) {
11584 entry->sampled = TRUE;
11588 stsd_entry_data += len;
11589 remaining_stsd_len -= len;
11593 /* collect sample information */
11594 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
11595 goto samples_failed;
11597 if (qtdemux->fragmented) {
11600 /* need all moov samples as basis; probably not many if any at all */
11601 /* prevent moof parsing taking of at this time */
11602 offset = qtdemux->moof_offset;
11603 qtdemux->moof_offset = 0;
11604 if (stream->n_samples &&
11605 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
11606 qtdemux->moof_offset = offset;
11607 goto samples_failed;
11609 qtdemux->moof_offset = 0;
11610 /* movie duration more reliable in this case (e.g. mehd) */
11611 if (qtdemux->segment.duration &&
11612 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
11614 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
11617 /* configure segments */
11618 if (!qtdemux_parse_segments (qtdemux, stream, trak))
11619 goto segments_failed;
11621 /* add some language tag, if useful */
11622 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
11623 strcmp (stream->lang_id, "und")) {
11624 const gchar *lang_code;
11626 /* convert ISO 639-2 code to ISO 639-1 */
11627 lang_code = gst_tag_get_language_code (stream->lang_id);
11628 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11629 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
11632 /* Check for UDTA tags */
11633 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
11634 qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
11637 /* now we are ready to add the stream */
11638 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
11639 goto too_many_streams;
11641 if (!qtdemux->got_moov) {
11642 qtdemux->streams[qtdemux->n_streams] = stream;
11643 qtdemux->n_streams++;
11644 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
11652 GST_INFO_OBJECT (qtdemux, "skip disabled track");
11654 gst_qtdemux_stream_free (qtdemux, stream);
11659 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
11660 (_("This file is corrupt and cannot be played.")), (NULL));
11662 gst_qtdemux_stream_free (qtdemux, stream);
11667 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
11669 gst_qtdemux_stream_free (qtdemux, stream);
11675 /* we posted an error already */
11676 /* free stbl sub-atoms */
11677 gst_qtdemux_stbl_free (stream);
11679 gst_qtdemux_stream_free (qtdemux, stream);
11684 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
11687 gst_qtdemux_stream_free (qtdemux, stream);
11692 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
11693 GST_FOURCC_ARGS (stream->subtype));
11695 gst_qtdemux_stream_free (qtdemux, stream);
11700 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
11701 (_("This file contains too many streams. Only playing first %d"),
11702 GST_QTDEMUX_MAX_STREAMS), (NULL));
11707 /* If we can estimate the overall bitrate, and don't have information about the
11708 * stream bitrate for exactly one stream, this guesses the stream bitrate as
11709 * the overall bitrate minus the sum of the bitrates of all other streams. This
11710 * should be useful for the common case where we have one audio and one video
11711 * stream and can estimate the bitrate of one, but not the other. */
11713 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
11715 QtDemuxStream *stream = NULL;
11716 gint64 size, sys_bitrate, sum_bitrate = 0;
11717 GstClockTime duration;
11721 if (qtdemux->fragmented)
11724 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
11726 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
11728 GST_DEBUG_OBJECT (qtdemux,
11729 "Size in bytes of the stream not known - bailing");
11733 /* Subtract the header size */
11734 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
11735 size, qtdemux->header_size);
11737 if (size < qtdemux->header_size)
11740 size = size - qtdemux->header_size;
11742 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
11743 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
11747 for (i = 0; i < qtdemux->n_streams; i++) {
11748 switch (qtdemux->streams[i]->subtype) {
11751 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
11752 CUR_STREAM (qtdemux->streams[i])->caps);
11753 /* retrieve bitrate, prefer avg then max */
11755 if (qtdemux->streams[i]->stream_tags) {
11756 if (gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags,
11757 GST_TAG_MAXIMUM_BITRATE, &bitrate))
11758 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
11759 if (gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags,
11760 GST_TAG_NOMINAL_BITRATE, &bitrate))
11761 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
11762 if (gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags,
11763 GST_TAG_BITRATE, &bitrate))
11764 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
11767 sum_bitrate += bitrate;
11770 GST_DEBUG_OBJECT (qtdemux,
11771 ">1 stream with unknown bitrate - bailing");
11774 stream = qtdemux->streams[i];
11778 /* For other subtypes, we assume no significant impact on bitrate */
11784 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
11788 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
11790 if (sys_bitrate < sum_bitrate) {
11791 /* This can happen, since sum_bitrate might be derived from maximum
11792 * bitrates and not average bitrates */
11793 GST_DEBUG_OBJECT (qtdemux,
11794 "System bitrate less than sum bitrate - bailing");
11798 bitrate = sys_bitrate - sum_bitrate;
11799 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
11800 ", Stream bitrate = %u", sys_bitrate, bitrate);
11802 if (!stream->stream_tags)
11803 stream->stream_tags = gst_tag_list_new_empty ();
11805 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
11807 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11808 GST_TAG_BITRATE, bitrate, NULL);
11811 static GstFlowReturn
11812 qtdemux_prepare_streams (GstQTDemux * qtdemux)
11815 GstFlowReturn ret = GST_FLOW_OK;
11817 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
11819 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
11820 QtDemuxStream *stream = qtdemux->streams[i];
11821 guint32 sample_num = 0;
11823 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
11824 i, stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
11826 if (qtdemux->fragmented) {
11827 /* need all moov samples first */
11828 GST_OBJECT_LOCK (qtdemux);
11829 while (stream->n_samples == 0)
11830 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
11832 GST_OBJECT_UNLOCK (qtdemux);
11834 /* discard any stray moof */
11835 qtdemux->moof_offset = 0;
11838 /* prepare braking */
11839 if (ret != GST_FLOW_ERROR)
11842 /* in pull mode, we should have parsed some sample info by now;
11843 * and quite some code will not handle no samples.
11844 * in push mode, we'll just have to deal with it */
11845 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
11846 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
11847 gst_qtdemux_remove_stream (qtdemux, i);
11852 /* parse the initial sample for use in setting the frame rate cap */
11853 while (sample_num == 0 && sample_num < stream->n_samples) {
11854 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
11858 if (stream->n_samples > 0 && stream->stbl_index >= 0) {
11859 stream->first_duration = stream->samples[0].duration;
11860 GST_LOG_OBJECT (qtdemux, "stream %d first duration %u",
11861 stream->track_id, stream->first_duration);
11868 static GstFlowReturn
11869 qtdemux_expose_streams (GstQTDemux * qtdemux)
11872 GSList *oldpads = NULL;
11875 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
11877 for (i = 0; i < qtdemux->n_streams; i++) {
11878 QtDemuxStream *stream = qtdemux->streams[i];
11879 GstPad *oldpad = stream->pad;
11882 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
11883 i, stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
11885 if ((stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl) &&
11886 stream->track_id == qtdemux->chapters_track_id) {
11887 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
11888 so that it doesn't look like a subtitle track */
11889 gst_qtdemux_remove_stream (qtdemux, i);
11894 /* now we have all info and can expose */
11895 list = stream->stream_tags;
11896 stream->stream_tags = NULL;
11898 oldpads = g_slist_prepend (oldpads, oldpad);
11899 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
11900 return GST_FLOW_ERROR;
11903 gst_qtdemux_guess_bitrate (qtdemux);
11905 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
11907 for (iter = oldpads; iter; iter = g_slist_next (iter)) {
11908 GstPad *oldpad = iter->data;
11911 event = gst_event_new_eos ();
11912 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
11913 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
11915 gst_pad_push_event (oldpad, event);
11916 gst_pad_set_active (oldpad, FALSE);
11917 gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
11918 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, oldpad);
11919 gst_object_unref (oldpad);
11922 /* check if we should post a redirect in case there is a single trak
11923 * and it is a redirecting trak */
11924 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
11927 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
11928 "an external content");
11929 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
11930 gst_structure_new ("redirect",
11931 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
11933 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
11934 qtdemux->posted_redirect = TRUE;
11937 for (i = 0; i < qtdemux->n_streams; i++) {
11938 QtDemuxStream *stream = qtdemux->streams[i];
11940 qtdemux_do_allocation (qtdemux, stream);
11943 qtdemux->exposed = TRUE;
11944 return GST_FLOW_OK;
11947 /* check if major or compatible brand is 3GP */
11948 static inline gboolean
11949 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
11952 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
11954 } else if (qtdemux->comp_brands != NULL) {
11958 gboolean res = FALSE;
11960 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
11963 while (size >= 4) {
11964 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
11969 gst_buffer_unmap (qtdemux->comp_brands, &map);
11976 /* check if tag is a spec'ed 3GP tag keyword storing a string */
11977 static inline gboolean
11978 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
11980 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
11981 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
11982 || fourcc == FOURCC_albm;
11986 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
11987 const char *tag, const char *dummy, GNode * node)
11989 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11993 gdouble longitude, latitude, altitude;
11996 len = QT_UINT32 (node->data);
12003 /* TODO: language code skipped */
12005 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
12008 /* do not alarm in trivial case, but bail out otherwise */
12009 if (*(data + offset) != 0) {
12010 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
12014 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
12015 GST_TAG_GEO_LOCATION_NAME, name, NULL);
12016 offset += strlen (name);
12020 if (len < offset + 2 + 4 + 4 + 4)
12023 /* +1 +1 = skip null-terminator and location role byte */
12025 /* table in spec says unsigned, semantics say negative has meaning ... */
12026 longitude = QT_SFP32 (data + offset);
12029 latitude = QT_SFP32 (data + offset);
12032 altitude = QT_SFP32 (data + offset);
12034 /* one invalid means all are invalid */
12035 if (longitude >= -180.0 && longitude <= 180.0 &&
12036 latitude >= -90.0 && latitude <= 90.0) {
12037 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
12038 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
12039 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
12040 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
12043 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
12050 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
12057 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
12058 const char *tag, const char *dummy, GNode * node)
12064 len = QT_UINT32 (node->data);
12068 y = QT_UINT16 ((guint8 *) node->data + 12);
12070 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
12073 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
12075 date = g_date_new_dmy (1, 1, y);
12076 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
12077 g_date_free (date);
12081 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
12082 const char *tag, const char *dummy, GNode * node)
12085 char *tag_str = NULL;
12090 len = QT_UINT32 (node->data);
12095 entity = (guint8 *) node->data + offset;
12096 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
12097 GST_DEBUG_OBJECT (qtdemux,
12098 "classification info: %c%c%c%c invalid classification entity",
12099 entity[0], entity[1], entity[2], entity[3]);
12104 table = QT_UINT16 ((guint8 *) node->data + offset);
12106 /* Language code skipped */
12110 /* Tag format: "XXXX://Y[YYYY]/classification info string"
12111 * XXXX: classification entity, fixed length 4 chars.
12112 * Y[YYYY]: classification table, max 5 chars.
12114 tag_str = g_strdup_printf ("----://%u/%s",
12115 table, (char *) node->data + offset);
12117 /* memcpy To be sure we're preserving byte order */
12118 memcpy (tag_str, entity, 4);
12119 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
12121 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
12130 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
12136 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
12137 const char *tag, const char *dummy, GNode * node)
12139 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12145 gboolean ret = TRUE;
12146 const gchar *charset = NULL;
12148 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12150 len = QT_UINT32 (data->data);
12151 type = QT_UINT32 ((guint8 *) data->data + 8);
12152 if (type == 0x00000001 && len > 16) {
12153 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
12156 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
12157 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
12160 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
12164 len = QT_UINT32 (node->data);
12165 type = QT_UINT32 ((guint8 *) node->data + 4);
12166 if ((type >> 24) == 0xa9 && len > 8 + 4) {
12170 /* Type starts with the (C) symbol, so the next data is a list
12171 * of (string size(16), language code(16), string) */
12173 str_len = QT_UINT16 ((guint8 *) node->data + 8);
12174 lang_code = QT_UINT16 ((guint8 *) node->data + 10);
12176 /* the string + fourcc + size + 2 16bit fields,
12177 * means that there are more tags in this atom */
12178 if (len > str_len + 8 + 4) {
12179 /* TODO how to represent the same tag in different languages? */
12180 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
12181 "text alternatives, reading only first one");
12185 len = MIN (len, str_len + 8 + 4); /* remove trailing strings that we don't use */
12186 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
12188 if (lang_code < 0x800) { /* MAC encoded string */
12191 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
12192 QT_FOURCC ((guint8 *) node->data + 4))) {
12193 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
12195 /* we go for 3GP style encoding if major brands claims so,
12196 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
12197 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
12198 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
12199 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
12201 /* 16-bit Language code is ignored here as well */
12202 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
12209 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
12210 ret = FALSE; /* may have to fallback */
12213 GError *err = NULL;
12215 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
12216 charset, NULL, NULL, &err);
12218 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
12219 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
12221 g_error_free (err);
12224 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
12225 len - offset, env_vars);
12228 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
12229 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
12233 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
12240 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
12241 const char *tag, const char *dummy, GNode * node)
12243 qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
12247 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
12248 const char *tag, const char *dummy, GNode * node)
12250 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12252 char *s, *t, *k = NULL;
12257 /* first try normal string tag if major brand not 3GP */
12258 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
12259 if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
12260 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
12261 * let's try it 3gpp way after minor safety check */
12263 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
12269 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
12273 len = QT_UINT32 (data);
12277 count = QT_UINT8 (data + 14);
12279 for (; count; count--) {
12282 if (offset + 1 > len)
12284 slen = QT_UINT8 (data + offset);
12286 if (offset + slen > len)
12288 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
12291 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
12293 t = g_strjoin (",", k, s, NULL);
12301 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
12308 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
12309 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
12318 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
12324 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
12325 const char *tag1, const char *tag2, GNode * node)
12332 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12334 len = QT_UINT32 (data->data);
12335 type = QT_UINT32 ((guint8 *) data->data + 8);
12336 if (type == 0x00000000 && len >= 22) {
12337 n1 = QT_UINT16 ((guint8 *) data->data + 18);
12338 n2 = QT_UINT16 ((guint8 *) data->data + 20);
12340 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
12341 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
12344 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
12345 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
12352 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
12353 const char *tag1, const char *dummy, GNode * node)
12360 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12362 len = QT_UINT32 (data->data);
12363 type = QT_UINT32 ((guint8 *) data->data + 8);
12364 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
12365 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
12366 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
12367 n1 = QT_UINT16 ((guint8 *) data->data + 16);
12369 /* do not add bpm=0 */
12370 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
12371 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
12379 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
12380 const char *tag1, const char *dummy, GNode * node)
12387 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12389 len = QT_UINT32 (data->data);
12390 type = QT_UINT32 ((guint8 *) data->data + 8);
12391 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
12392 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
12393 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
12394 num = QT_UINT32 ((guint8 *) data->data + 16);
12396 /* do not add num=0 */
12397 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
12398 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
12405 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
12406 const char *tag1, const char *dummy, GNode * node)
12413 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12415 len = QT_UINT32 (data->data);
12416 type = QT_UINT32 ((guint8 *) data->data + 8);
12417 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
12418 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
12419 GstTagImageType image_type;
12421 if (gst_tag_list_get_tag_size (taglist, GST_TAG_IMAGE) == 0)
12422 image_type = GST_TAG_IMAGE_TYPE_FRONT_COVER;
12424 image_type = GST_TAG_IMAGE_TYPE_NONE;
12427 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
12428 len - 16, image_type))) {
12429 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
12430 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
12431 gst_sample_unref (sample);
12438 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
12439 const char *tag, const char *dummy, GNode * node)
12446 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12448 len = QT_UINT32 (data->data);
12449 type = QT_UINT32 ((guint8 *) data->data + 8);
12450 if (type == 0x00000001 && len > 16) {
12451 guint y, m = 1, d = 1;
12454 s = g_strndup ((char *) data->data + 16, len - 16);
12455 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
12456 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
12457 if (ret >= 1 && y > 1500 && y < 3000) {
12460 date = g_date_new_dmy (d, m, y);
12461 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
12462 g_date_free (date);
12464 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
12472 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
12473 const char *tag, const char *dummy, GNode * node)
12477 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12479 /* re-route to normal string tag if major brand says so
12480 * or no data atom and compatible brand suggests so */
12481 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
12482 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
12483 qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
12488 guint len, type, n;
12490 len = QT_UINT32 (data->data);
12491 type = QT_UINT32 ((guint8 *) data->data + 8);
12492 if (type == 0x00000000 && len >= 18) {
12493 n = QT_UINT16 ((guint8 *) data->data + 16);
12495 const gchar *genre;
12497 genre = gst_tag_id3_genre_get (n - 1);
12498 if (genre != NULL) {
12499 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
12500 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
12508 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
12509 const gchar * tag, guint8 * data, guint32 datasize)
12514 /* make a copy to have \0 at the end */
12515 datacopy = g_strndup ((gchar *) data, datasize);
12517 /* convert the str to double */
12518 if (sscanf (datacopy, "%lf", &value) == 1) {
12519 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
12520 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
12522 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
12530 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
12531 const char *tag, const char *tag_bis, GNode * node)
12540 const gchar *meanstr;
12541 const gchar *namestr;
12543 /* checking the whole ---- atom size for consistency */
12544 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
12545 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
12549 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
12551 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
12555 meansize = QT_UINT32 (mean->data);
12556 if (meansize <= 12) {
12557 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
12560 meanstr = ((gchar *) mean->data) + 12;
12563 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
12565 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
12569 namesize = QT_UINT32 (name->data);
12570 if (namesize <= 12) {
12571 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
12574 namestr = ((gchar *) name->data) + 12;
12582 * uint24 - data type
12586 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12588 GST_WARNING_OBJECT (demux, "No data atom in this tag");
12591 datasize = QT_UINT32 (data->data);
12592 if (datasize <= 16) {
12593 GST_WARNING_OBJECT (demux, "Data atom too small");
12596 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
12598 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
12599 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
12600 static const struct
12602 const gchar name[28];
12603 const gchar tag[28];
12606 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
12607 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
12608 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
12609 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
12610 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
12611 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
12612 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
12613 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
12617 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
12618 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
12619 switch (gst_tag_get_type (tags[i].tag)) {
12620 case G_TYPE_DOUBLE:
12621 qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
12622 ((guint8 *) data->data) + 16, datasize - 16);
12624 case G_TYPE_STRING:
12625 qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
12634 if (i == G_N_ELEMENTS (tags))
12644 #ifndef GST_DISABLE_GST_DEBUG
12646 gchar *namestr_dbg;
12647 gchar *meanstr_dbg;
12649 meanstr_dbg = g_strndup (meanstr, meansize);
12650 namestr_dbg = g_strndup (namestr, namesize);
12652 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
12653 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
12655 g_free (namestr_dbg);
12656 g_free (meanstr_dbg);
12663 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
12664 const char *tag_bis, GNode * node)
12669 GstTagList *id32_taglist = NULL;
12671 GST_LOG_OBJECT (demux, "parsing ID32");
12674 len = GST_READ_UINT32_BE (data);
12676 /* need at least full box and language tag */
12680 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
12681 gst_buffer_fill (buf, 0, data + 14, len - 14);
12683 id32_taglist = gst_tag_list_from_id3v2_tag (buf);
12684 if (id32_taglist) {
12685 GST_LOG_OBJECT (demux, "parsing ok");
12686 gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
12687 gst_tag_list_unref (id32_taglist);
12689 GST_LOG_OBJECT (demux, "parsing failed");
12692 gst_buffer_unref (buf);
12695 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
12696 const char *tag, const char *tag_bis, GNode * node);
12699 FOURCC_pcst -> if media is a podcast -> bool
12700 FOURCC_cpil -> if media is part of a compilation -> bool
12701 FOURCC_pgap -> if media is part of a gapless context -> bool
12702 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
12705 static const struct
12708 const gchar *gst_tag;
12709 const gchar *gst_tag_bis;
12710 const GstQTDemuxAddTagFunc func;
12713 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
12714 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
12715 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
12716 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
12717 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
12718 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
12719 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
12720 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
12721 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
12722 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
12723 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
12724 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
12725 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
12726 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12727 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12728 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12729 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
12730 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
12731 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
12732 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
12733 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
12734 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
12735 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
12736 qtdemux_tag_add_num}, {
12737 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
12738 qtdemux_tag_add_num}, {
12739 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
12740 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
12741 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
12742 FOURCC_covr, GST_TAG_IMAGE, NULL, qtdemux_tag_add_covr}, {
12743 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
12744 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
12745 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
12746 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
12747 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
12748 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
12749 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
12750 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
12751 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
12752 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
12753 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
12754 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
12755 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
12756 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
12757 qtdemux_tag_add_classification}, {
12758 FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
12759 FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
12760 FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
12762 /* This is a special case, some tags are stored in this
12763 * 'reverse dns naming', according to:
12764 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
12767 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
12768 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
12769 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
12772 struct _GstQtDemuxTagList
12775 GstTagList *taglist;
12777 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
12780 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
12786 const gchar *style;
12791 GstQTDemux *demux = qtdemuxtaglist->demux;
12792 GstTagList *taglist = qtdemuxtaglist->taglist;
12795 len = QT_UINT32 (data);
12796 buf = gst_buffer_new_and_alloc (len);
12797 gst_buffer_fill (buf, 0, data, len);
12799 /* heuristic to determine style of tag */
12800 if (QT_FOURCC (data + 4) == FOURCC_____ ||
12801 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
12803 else if (demux->major_brand == FOURCC_qt__)
12804 style = "quicktime";
12805 /* fall back to assuming iso/3gp tag style */
12809 /* santize the name for the caps. */
12810 for (i = 0; i < 4; i++) {
12811 guint8 d = data[4 + i];
12812 if (g_ascii_isalnum (d))
12813 ndata[i] = g_ascii_tolower (d);
12818 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
12819 ndata[0], ndata[1], ndata[2], ndata[3]);
12820 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
12822 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
12823 sample = gst_sample_new (buf, NULL, NULL, s);
12824 gst_buffer_unref (buf);
12825 g_free (media_type);
12827 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
12830 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
12831 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
12833 gst_sample_unref (sample);
12837 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
12844 GstQtDemuxTagList demuxtaglist;
12846 demuxtaglist.demux = qtdemux;
12847 demuxtaglist.taglist = taglist;
12849 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
12850 if (meta != NULL) {
12851 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
12852 if (ilst == NULL) {
12853 GST_LOG_OBJECT (qtdemux, "no ilst");
12858 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
12862 while (i < G_N_ELEMENTS (add_funcs)) {
12863 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
12867 len = QT_UINT32 (node->data);
12869 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
12870 GST_FOURCC_ARGS (add_funcs[i].fourcc));
12872 add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
12873 add_funcs[i].gst_tag_bis, node);
12875 g_node_destroy (node);
12881 /* parsed nodes have been removed, pass along remainder as blob */
12882 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
12883 (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
12885 /* parse up XMP_ node if existing */
12886 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
12887 if (xmp_ != NULL) {
12889 GstTagList *xmptaglist;
12891 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
12892 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
12893 xmptaglist = gst_tag_list_from_xmp_buffer (buf);
12894 gst_buffer_unref (buf);
12896 qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
12898 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
12904 GstStructure *structure; /* helper for sort function */
12906 guint min_req_bitrate;
12907 guint min_req_qt_version;
12911 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
12913 GstQtReference *ref_a = (GstQtReference *) a;
12914 GstQtReference *ref_b = (GstQtReference *) b;
12916 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
12917 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
12919 /* known bitrates go before unknown; higher bitrates go first */
12920 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
12923 /* sort the redirects and post a message for the application.
12926 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
12928 GstQtReference *best;
12931 GValue list_val = { 0, };
12934 g_assert (references != NULL);
12936 references = g_list_sort (references, qtdemux_redirects_sort_func);
12938 best = (GstQtReference *) references->data;
12940 g_value_init (&list_val, GST_TYPE_LIST);
12942 for (l = references; l != NULL; l = l->next) {
12943 GstQtReference *ref = (GstQtReference *) l->data;
12944 GValue struct_val = { 0, };
12946 ref->structure = gst_structure_new ("redirect",
12947 "new-location", G_TYPE_STRING, ref->location, NULL);
12949 if (ref->min_req_bitrate > 0) {
12950 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
12951 ref->min_req_bitrate, NULL);
12954 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
12955 g_value_set_boxed (&struct_val, ref->structure);
12956 gst_value_list_append_value (&list_val, &struct_val);
12957 g_value_unset (&struct_val);
12958 /* don't free anything here yet, since we need best->structure below */
12961 g_assert (best != NULL);
12962 s = gst_structure_copy (best->structure);
12964 if (g_list_length (references) > 1) {
12965 gst_structure_set_value (s, "locations", &list_val);
12968 g_value_unset (&list_val);
12970 for (l = references; l != NULL; l = l->next) {
12971 GstQtReference *ref = (GstQtReference *) l->data;
12973 gst_structure_free (ref->structure);
12974 g_free (ref->location);
12977 g_list_free (references);
12979 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
12980 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
12981 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
12982 qtdemux->posted_redirect = TRUE;
12985 /* look for redirect nodes, collect all redirect information and
12989 qtdemux_parse_redirects (GstQTDemux * qtdemux)
12991 GNode *rmra, *rmda, *rdrf;
12993 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
12995 GList *redirects = NULL;
12997 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
12999 GstQtReference ref = { NULL, NULL, 0, 0 };
13000 GNode *rmdr, *rmvc;
13002 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
13003 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
13004 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
13005 ref.min_req_bitrate);
13008 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
13009 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
13010 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
13012 #ifndef GST_DISABLE_GST_DEBUG
13013 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
13015 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
13017 GST_LOG_OBJECT (qtdemux,
13018 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
13019 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
13020 bitmask, check_type);
13021 if (package == FOURCC_qtim && check_type == 0) {
13022 ref.min_req_qt_version = version;
13026 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
13032 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
13033 if (ref_len > 20) {
13034 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
13035 ref_data = (guint8 *) rdrf->data + 20;
13036 if (ref_type == FOURCC_alis) {
13037 guint record_len, record_version, fn_len;
13039 if (ref_len > 70) {
13040 /* MacOSX alias record, google for alias-layout.txt */
13041 record_len = QT_UINT16 (ref_data + 4);
13042 record_version = QT_UINT16 (ref_data + 4 + 2);
13043 fn_len = QT_UINT8 (ref_data + 50);
13044 if (record_len > 50 && record_version == 2 && fn_len > 0) {
13045 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
13048 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
13051 } else if (ref_type == FOURCC_url_) {
13052 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
13054 GST_DEBUG_OBJECT (qtdemux,
13055 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
13056 GST_FOURCC_ARGS (ref_type));
13058 if (ref.location != NULL) {
13059 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
13061 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
13063 GST_WARNING_OBJECT (qtdemux,
13064 "Failed to extract redirect location from rdrf atom");
13067 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
13071 /* look for others */
13072 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
13075 if (redirects != NULL) {
13076 qtdemux_process_redirects (qtdemux, redirects);
13082 static GstTagList *
13083 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
13087 if (tags == NULL) {
13088 tags = gst_tag_list_new_empty ();
13089 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
13092 if (qtdemux->major_brand == FOURCC_mjp2)
13093 fmt = "Motion JPEG 2000";
13094 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
13096 else if (qtdemux->major_brand == FOURCC_qt__)
13098 else if (qtdemux->fragmented)
13101 fmt = "ISO MP4/M4A";
13103 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
13104 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
13106 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
13112 /* we have read the complete moov node now.
13113 * This function parses all of the relevant info, creates the traks and
13114 * prepares all data structures for playback
13117 qtdemux_parse_tree (GstQTDemux * qtdemux)
13123 GstClockTime duration;
13125 guint64 creation_time;
13126 GstDateTime *datetime = NULL;
13129 /* make sure we have a usable taglist */
13130 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13132 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
13133 if (mvhd == NULL) {
13134 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
13135 return qtdemux_parse_redirects (qtdemux);
13138 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
13139 if (version == 1) {
13140 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
13141 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
13142 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
13143 } else if (version == 0) {
13144 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
13145 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
13146 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
13148 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
13152 /* Moving qt creation time (secs since 1904) to unix time */
13153 if (creation_time != 0) {
13154 /* Try to use epoch first as it should be faster and more commonly found */
13155 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
13158 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
13159 /* some data cleansing sanity */
13160 g_get_current_time (&now);
13161 if (now.tv_sec + 24 * 3600 < creation_time) {
13162 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
13164 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
13167 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
13168 GDateTime *dt, *dt_local;
13170 dt = g_date_time_add_seconds (base_dt, creation_time);
13171 dt_local = g_date_time_to_local (dt);
13172 datetime = gst_date_time_new_from_g_date_time (dt_local);
13174 g_date_time_unref (base_dt);
13175 g_date_time_unref (dt);
13179 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
13180 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
13182 gst_date_time_unref (datetime);
13185 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
13186 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
13188 /* check for fragmented file and get some (default) data */
13189 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
13192 GstByteReader mehd_data;
13194 /* let track parsing or anyone know weird stuff might happen ... */
13195 qtdemux->fragmented = TRUE;
13197 /* compensate for total duration */
13198 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
13200 qtdemux_parse_mehd (qtdemux, &mehd_data);
13203 /* set duration in the segment info */
13204 gst_qtdemux_get_duration (qtdemux, &duration);
13206 qtdemux->segment.duration = duration;
13207 /* also do not exceed duration; stop is set that way post seek anyway,
13208 * and segment activation falls back to duration,
13209 * whereas loop only checks stop, so let's align this here as well */
13210 qtdemux->segment.stop = duration;
13213 /* parse all traks */
13214 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
13216 qtdemux_parse_trak (qtdemux, trak);
13217 /* iterate all siblings */
13218 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
13221 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13224 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
13226 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13228 GST_LOG_OBJECT (qtdemux, "No udta node found.");
13231 /* maybe also some tags in meta box */
13232 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
13234 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
13235 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13237 GST_LOG_OBJECT (qtdemux, "No meta node found.");
13240 /* parse any protection system info */
13241 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
13243 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
13244 qtdemux_parse_pssh (qtdemux, pssh);
13245 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
13248 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
13253 /* taken from ffmpeg */
13255 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
13267 len = (len << 7) | (c & 0x7f);
13275 /* this can change the codec originally present in @list */
13277 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
13278 QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
13280 int len = QT_UINT32 (esds->data);
13281 guint8 *ptr = esds->data;
13282 guint8 *end = ptr + len;
13284 guint8 *data_ptr = NULL;
13286 guint8 object_type_id = 0;
13287 const char *codec_name = NULL;
13288 GstCaps *caps = NULL;
13290 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
13292 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
13294 while (ptr + 1 < end) {
13295 tag = QT_UINT8 (ptr);
13296 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
13298 len = read_descr_size (ptr, end, &ptr);
13299 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
13301 /* Check the stated amount of data is available for reading */
13302 if (len < 0 || ptr + len > end)
13306 case ES_DESCRIPTOR_TAG:
13307 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
13308 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
13311 case DECODER_CONFIG_DESC_TAG:{
13312 guint max_bitrate, avg_bitrate;
13314 object_type_id = QT_UINT8 (ptr);
13315 max_bitrate = QT_UINT32 (ptr + 5);
13316 avg_bitrate = QT_UINT32 (ptr + 9);
13317 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
13318 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
13319 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
13320 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
13321 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
13322 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
13323 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
13324 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
13326 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
13327 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
13328 avg_bitrate, NULL);
13333 case DECODER_SPECIFIC_INFO_TAG:
13334 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
13335 if (object_type_id == 0xe0 && len == 0x40) {
13341 GST_DEBUG_OBJECT (qtdemux,
13342 "Have VOBSUB palette. Creating palette event");
13343 /* move to decConfigDescr data and read palette */
13345 for (i = 0; i < 16; i++) {
13346 clut[i] = QT_UINT32 (data);
13350 s = gst_structure_new ("application/x-gst-dvd", "event",
13351 G_TYPE_STRING, "dvd-spu-clut-change",
13352 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
13353 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
13354 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
13355 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
13356 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
13357 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
13358 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
13359 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
13362 /* store event and trigger custom processing */
13363 stream->pending_event =
13364 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
13366 /* Generic codec_data handler puts it on the caps */
13373 case SL_CONFIG_DESC_TAG:
13374 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
13378 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
13380 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
13386 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
13387 * in use, and should also be used to override some other parameters for some
13389 switch (object_type_id) {
13390 case 0x20: /* MPEG-4 */
13391 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
13392 * profile_and_level_indication */
13393 if (data_ptr != NULL && data_len >= 5 &&
13394 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
13395 gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
13396 data_ptr + 4, data_len - 4);
13398 break; /* Nothing special needed here */
13399 case 0x21: /* H.264 */
13400 codec_name = "H.264 / AVC";
13401 caps = gst_caps_new_simple ("video/x-h264",
13402 "stream-format", G_TYPE_STRING, "avc",
13403 "alignment", G_TYPE_STRING, "au", NULL);
13405 case 0x40: /* AAC (any) */
13406 case 0x66: /* AAC Main */
13407 case 0x67: /* AAC LC */
13408 case 0x68: /* AAC SSR */
13409 /* Override channels and rate based on the codec_data, as it's often
13411 /* Only do so for basic setup without HE-AAC extension */
13412 if (data_ptr && data_len == 2) {
13413 guint channels, rate;
13415 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
13417 entry->n_channels = channels;
13419 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
13421 entry->rate = rate;
13424 /* Set level and profile if possible */
13425 if (data_ptr != NULL && data_len >= 2) {
13426 gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
13427 data_ptr, data_len);
13429 const gchar *profile_str = NULL;
13432 guint8 *codec_data;
13433 gint rate_idx, profile;
13435 /* No codec_data, let's invent something.
13436 * FIXME: This is wrong for SBR! */
13438 GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
13440 buffer = gst_buffer_new_and_alloc (2);
13441 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
13442 codec_data = map.data;
13445 gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
13448 switch (object_type_id) {
13450 profile_str = "main";
13454 profile_str = "lc";
13458 profile_str = "ssr";
13466 codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
13468 ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
13470 gst_buffer_unmap (buffer, &map);
13471 gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
13472 GST_TYPE_BUFFER, buffer, NULL);
13473 gst_buffer_unref (buffer);
13476 gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
13477 G_TYPE_STRING, profile_str, NULL);
13481 case 0x60: /* MPEG-2, various profiles */
13487 codec_name = "MPEG-2 video";
13488 caps = gst_caps_new_simple ("video/mpeg",
13489 "mpegversion", G_TYPE_INT, 2,
13490 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13492 case 0x69: /* MPEG-2 BC audio */
13493 case 0x6B: /* MPEG-1 audio */
13494 caps = gst_caps_new_simple ("audio/mpeg",
13495 "mpegversion", G_TYPE_INT, 1, NULL);
13496 codec_name = "MPEG-1 audio";
13498 case 0x6A: /* MPEG-1 */
13499 codec_name = "MPEG-1 video";
13500 caps = gst_caps_new_simple ("video/mpeg",
13501 "mpegversion", G_TYPE_INT, 1,
13502 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13504 case 0x6C: /* MJPEG */
13506 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13508 codec_name = "Motion-JPEG";
13510 case 0x6D: /* PNG */
13512 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
13514 codec_name = "PNG still images";
13516 case 0x6E: /* JPEG2000 */
13517 codec_name = "JPEG-2000";
13518 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
13520 case 0xA4: /* Dirac */
13521 codec_name = "Dirac";
13522 caps = gst_caps_new_empty_simple ("video/x-dirac");
13524 case 0xA5: /* AC3 */
13525 codec_name = "AC-3 audio";
13526 caps = gst_caps_new_simple ("audio/x-ac3",
13527 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13529 case 0xA9: /* AC3 */
13530 codec_name = "DTS audio";
13531 caps = gst_caps_new_simple ("audio/x-dts",
13532 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13534 case 0xE1: /* QCELP */
13535 /* QCELP, the codec_data is a riff tag (little endian) with
13536 * 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). */
13537 caps = gst_caps_new_empty_simple ("audio/qcelp");
13538 codec_name = "QCELP";
13544 /* If we have a replacement caps, then change our caps for this stream */
13546 gst_caps_unref (entry->caps);
13547 entry->caps = caps;
13550 if (codec_name && list)
13551 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
13552 GST_TAG_AUDIO_CODEC, codec_name, NULL);
13554 /* Add the codec_data attribute to caps, if we have it */
13558 buffer = gst_buffer_new_and_alloc (data_len);
13559 gst_buffer_fill (buffer, 0, data_ptr, data_len);
13561 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
13562 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
13564 gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
13566 gst_buffer_unref (buffer);
13571 static inline GstCaps *
13572 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
13576 char *s, fourstr[5];
13578 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13579 for (i = 0; i < 4; i++) {
13580 if (!g_ascii_isalnum (fourstr[i]))
13583 s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
13584 caps = gst_caps_new_empty_simple (s);
13589 #define _codec(name) \
13591 if (codec_name) { \
13592 *codec_name = g_strdup (name); \
13597 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13598 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
13599 const guint8 * stsd_entry_data, gchar ** codec_name)
13601 GstCaps *caps = NULL;
13602 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
13606 _codec ("PNG still images");
13607 caps = gst_caps_new_empty_simple ("image/png");
13610 _codec ("JPEG still images");
13612 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13615 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
13616 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
13617 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
13618 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
13619 _codec ("Motion-JPEG");
13621 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13624 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
13625 _codec ("Motion-JPEG format B");
13626 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
13629 _codec ("JPEG-2000");
13630 /* override to what it should be according to spec, avoid palette_data */
13631 entry->bits_per_sample = 24;
13632 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
13635 _codec ("Sorensen video v.3");
13636 caps = gst_caps_new_simple ("video/x-svq",
13637 "svqversion", G_TYPE_INT, 3, NULL);
13639 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
13640 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
13641 _codec ("Sorensen video v.1");
13642 caps = gst_caps_new_simple ("video/x-svq",
13643 "svqversion", G_TYPE_INT, 1, NULL);
13645 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
13646 caps = gst_caps_new_empty_simple ("video/x-raw");
13647 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
13648 _codec ("Windows Raw RGB");
13649 stream->alignment = 32;
13655 bps = QT_UINT16 (stsd_entry_data + 82);
13658 format = GST_VIDEO_FORMAT_RGB15;
13661 format = GST_VIDEO_FORMAT_RGB16;
13664 format = GST_VIDEO_FORMAT_RGB;
13667 format = GST_VIDEO_FORMAT_ARGB;
13675 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
13676 format = GST_VIDEO_FORMAT_I420;
13678 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
13679 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
13680 format = GST_VIDEO_FORMAT_I420;
13683 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
13684 format = GST_VIDEO_FORMAT_UYVY;
13686 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
13687 format = GST_VIDEO_FORMAT_v308;
13689 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
13690 format = GST_VIDEO_FORMAT_v216;
13693 format = GST_VIDEO_FORMAT_v210;
13695 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
13696 format = GST_VIDEO_FORMAT_r210;
13698 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
13699 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
13700 format = GST_VIDEO_FORMAT_v410;
13703 /* Packed YUV 4:4:4:4 8 bit in 32 bits
13704 * but different order than AYUV
13705 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
13706 format = GST_VIDEO_FORMAT_v408;
13709 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
13710 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
13711 _codec ("MPEG-1 video");
13712 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
13713 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13715 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
13716 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
13717 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
13718 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
13719 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
13720 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
13721 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
13722 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
13723 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
13724 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
13725 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
13726 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
13727 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
13728 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
13729 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
13730 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
13731 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
13732 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
13733 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
13734 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
13735 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
13736 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
13737 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
13738 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
13739 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
13740 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
13741 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
13742 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
13743 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
13744 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
13745 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
13746 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
13747 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
13748 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
13749 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
13750 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
13751 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
13752 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
13753 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
13754 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
13755 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
13756 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
13757 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
13758 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
13759 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
13760 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
13761 case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
13762 _codec ("MPEG-2 video");
13763 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
13764 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13766 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
13767 _codec ("GIF still images");
13768 caps = gst_caps_new_empty_simple ("image/gif");
13771 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
13773 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
13775 /* ffmpeg uses the height/width props, don't know why */
13776 caps = gst_caps_new_simple ("video/x-h263",
13777 "variant", G_TYPE_STRING, "itu", NULL);
13781 _codec ("MPEG-4 video");
13782 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
13783 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13785 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
13786 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
13787 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
13788 caps = gst_caps_new_simple ("video/x-msmpeg",
13789 "msmpegversion", G_TYPE_INT, 43, NULL);
13791 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
13793 caps = gst_caps_new_simple ("video/x-divx",
13794 "divxversion", G_TYPE_INT, 3, NULL);
13796 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
13797 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
13799 caps = gst_caps_new_simple ("video/x-divx",
13800 "divxversion", G_TYPE_INT, 4, NULL);
13802 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
13804 caps = gst_caps_new_simple ("video/x-divx",
13805 "divxversion", G_TYPE_INT, 5, NULL);
13808 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
13810 caps = gst_caps_new_simple ("video/x-ffv",
13811 "ffvversion", G_TYPE_INT, 1, NULL);
13814 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
13815 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
13820 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
13821 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
13822 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13826 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
13827 _codec ("Cinepak");
13828 caps = gst_caps_new_empty_simple ("video/x-cinepak");
13830 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
13831 _codec ("Apple QuickDraw");
13832 caps = gst_caps_new_empty_simple ("video/x-qdrw");
13834 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
13835 _codec ("Apple video");
13836 caps = gst_caps_new_empty_simple ("video/x-apple-video");
13840 _codec ("H.264 / AVC");
13841 caps = gst_caps_new_simple ("video/x-h264",
13842 "stream-format", G_TYPE_STRING, "avc",
13843 "alignment", G_TYPE_STRING, "au", NULL);
13846 _codec ("H.264 / AVC");
13847 caps = gst_caps_new_simple ("video/x-h264",
13848 "stream-format", G_TYPE_STRING, "avc3",
13849 "alignment", G_TYPE_STRING, "au", NULL);
13853 _codec ("H.265 / HEVC");
13854 caps = gst_caps_new_simple ("video/x-h265",
13855 "stream-format", G_TYPE_STRING, "hvc1",
13856 "alignment", G_TYPE_STRING, "au", NULL);
13859 _codec ("H.265 / HEVC");
13860 caps = gst_caps_new_simple ("video/x-h265",
13861 "stream-format", G_TYPE_STRING, "hev1",
13862 "alignment", G_TYPE_STRING, "au", NULL);
13865 _codec ("Run-length encoding");
13866 caps = gst_caps_new_simple ("video/x-rle",
13867 "layout", G_TYPE_STRING, "quicktime", NULL);
13870 _codec ("Run-length encoding");
13871 caps = gst_caps_new_simple ("video/x-rle",
13872 "layout", G_TYPE_STRING, "microsoft", NULL);
13874 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
13875 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
13876 _codec ("Indeo Video 3");
13877 caps = gst_caps_new_simple ("video/x-indeo",
13878 "indeoversion", G_TYPE_INT, 3, NULL);
13880 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
13881 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
13882 _codec ("Intel Video 4");
13883 caps = gst_caps_new_simple ("video/x-indeo",
13884 "indeoversion", G_TYPE_INT, 4, NULL);
13888 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
13889 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
13890 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
13891 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
13892 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
13893 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
13894 _codec ("DV Video");
13895 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
13896 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13898 case FOURCC_dv5n: /* DVCPRO50 NTSC */
13899 case FOURCC_dv5p: /* DVCPRO50 PAL */
13900 _codec ("DVCPro50 Video");
13901 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
13902 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13904 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
13905 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
13906 _codec ("DVCProHD Video");
13907 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
13908 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13910 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
13911 _codec ("Apple Graphics (SMC)");
13912 caps = gst_caps_new_empty_simple ("video/x-smc");
13914 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
13916 caps = gst_caps_new_empty_simple ("video/x-vp3");
13918 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
13919 _codec ("VP6 Flash");
13920 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
13924 caps = gst_caps_new_empty_simple ("video/x-theora");
13925 /* theora uses one byte of padding in the data stream because it does not
13926 * allow 0 sized packets while theora does */
13927 entry->padding = 1;
13931 caps = gst_caps_new_empty_simple ("video/x-dirac");
13933 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
13934 _codec ("TIFF still images");
13935 caps = gst_caps_new_empty_simple ("image/tiff");
13937 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
13938 _codec ("Apple Intermediate Codec");
13939 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
13941 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
13942 _codec ("AVID DNxHD");
13943 caps = gst_caps_from_string ("video/x-dnxhd");
13947 _codec ("On2 VP8");
13948 caps = gst_caps_from_string ("video/x-vp8");
13951 _codec ("Google VP9");
13952 caps = gst_caps_from_string ("video/x-vp9");
13955 _codec ("Apple ProRes LT");
13957 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
13961 _codec ("Apple ProRes HQ");
13963 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
13967 _codec ("Apple ProRes");
13969 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13973 _codec ("Apple ProRes Proxy");
13975 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13979 _codec ("Apple ProRes 4444");
13981 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13985 _codec ("Apple ProRes 4444 XQ");
13987 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13991 _codec ("GoPro CineForm");
13992 caps = gst_caps_from_string ("video/x-cineform");
13997 caps = gst_caps_new_simple ("video/x-wmv",
13998 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
14000 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
14003 caps = _get_unknown_codec_name ("video", fourcc);
14008 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
14011 gst_video_info_init (&info);
14012 gst_video_info_set_format (&info, format, entry->width, entry->height);
14014 caps = gst_video_info_to_caps (&info);
14015 *codec_name = gst_pb_utils_get_codec_description (caps);
14017 /* enable clipping for raw video streams */
14018 stream->need_clip = TRUE;
14019 stream->alignment = 32;
14026 round_up_pow2 (guint n)
14038 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14039 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
14040 int len, gchar ** codec_name)
14043 const GstStructure *s;
14046 GstAudioFormat format = 0;
14049 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14051 depth = entry->bytes_per_packet * 8;
14054 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
14056 /* 8-bit audio is unsigned */
14058 format = GST_AUDIO_FORMAT_U8;
14059 /* otherwise it's signed and big-endian just like 'twos' */
14061 endian = G_BIG_ENDIAN;
14068 endian = G_LITTLE_ENDIAN;
14071 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
14073 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
14077 caps = gst_caps_new_simple ("audio/x-raw",
14078 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14079 "layout", G_TYPE_STRING, "interleaved", NULL);
14080 stream->alignment = GST_ROUND_UP_8 (depth);
14081 stream->alignment = round_up_pow2 (stream->alignment);
14084 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
14085 _codec ("Raw 64-bit floating-point audio");
14086 caps = gst_caps_new_simple ("audio/x-raw",
14087 "format", G_TYPE_STRING, "F64BE",
14088 "layout", G_TYPE_STRING, "interleaved", NULL);
14089 stream->alignment = 8;
14091 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
14092 _codec ("Raw 32-bit floating-point audio");
14093 caps = gst_caps_new_simple ("audio/x-raw",
14094 "format", G_TYPE_STRING, "F32BE",
14095 "layout", G_TYPE_STRING, "interleaved", NULL);
14096 stream->alignment = 4;
14099 _codec ("Raw 24-bit PCM audio");
14100 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14102 caps = gst_caps_new_simple ("audio/x-raw",
14103 "format", G_TYPE_STRING, "S24BE",
14104 "layout", G_TYPE_STRING, "interleaved", NULL);
14105 stream->alignment = 4;
14107 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
14108 _codec ("Raw 32-bit PCM audio");
14109 caps = gst_caps_new_simple ("audio/x-raw",
14110 "format", G_TYPE_STRING, "S32BE",
14111 "layout", G_TYPE_STRING, "interleaved", NULL);
14112 stream->alignment = 4;
14114 case GST_MAKE_FOURCC ('s', '1', '6', 'l'):
14115 _codec ("Raw 16-bit PCM audio");
14116 caps = gst_caps_new_simple ("audio/x-raw",
14117 "format", G_TYPE_STRING, "S16LE",
14118 "layout", G_TYPE_STRING, "interleaved", NULL);
14119 stream->alignment = 2;
14122 _codec ("Mu-law audio");
14123 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
14126 _codec ("A-law audio");
14127 caps = gst_caps_new_empty_simple ("audio/x-alaw");
14131 _codec ("Microsoft ADPCM");
14132 /* Microsoft ADPCM-ACM code 2 */
14133 caps = gst_caps_new_simple ("audio/x-adpcm",
14134 "layout", G_TYPE_STRING, "microsoft", NULL);
14138 _codec ("DVI/IMA ADPCM");
14139 caps = gst_caps_new_simple ("audio/x-adpcm",
14140 "layout", G_TYPE_STRING, "dvi", NULL);
14144 _codec ("DVI/Intel IMA ADPCM");
14145 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
14146 caps = gst_caps_new_simple ("audio/x-adpcm",
14147 "layout", G_TYPE_STRING, "quicktime", NULL);
14151 /* MPEG layer 3, CBR only (pre QT4.1) */
14153 _codec ("MPEG-1 layer 3");
14154 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
14155 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
14156 "mpegversion", G_TYPE_INT, 1, NULL);
14158 case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
14159 _codec ("MPEG-1 layer 2");
14161 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
14162 "mpegversion", G_TYPE_INT, 1, NULL);
14165 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
14166 _codec ("EAC-3 audio");
14167 caps = gst_caps_new_simple ("audio/x-eac3",
14168 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14169 entry->sampled = TRUE;
14171 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
14173 _codec ("AC-3 audio");
14174 caps = gst_caps_new_simple ("audio/x-ac3",
14175 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14176 entry->sampled = TRUE;
14178 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
14179 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
14180 _codec ("DTS audio");
14181 caps = gst_caps_new_simple ("audio/x-dts",
14182 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14183 entry->sampled = TRUE;
14185 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
14186 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
14187 _codec ("DTS-HD audio");
14188 caps = gst_caps_new_simple ("audio/x-dts",
14189 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14190 entry->sampled = TRUE;
14194 caps = gst_caps_new_simple ("audio/x-mace",
14195 "maceversion", G_TYPE_INT, 3, NULL);
14199 caps = gst_caps_new_simple ("audio/x-mace",
14200 "maceversion", G_TYPE_INT, 6, NULL);
14202 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
14204 caps = gst_caps_new_empty_simple ("application/ogg");
14206 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
14207 _codec ("DV audio");
14208 caps = gst_caps_new_empty_simple ("audio/x-dv");
14211 _codec ("MPEG-4 AAC audio");
14212 caps = gst_caps_new_simple ("audio/mpeg",
14213 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
14214 "stream-format", G_TYPE_STRING, "raw", NULL);
14216 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
14217 _codec ("QDesign Music");
14218 caps = gst_caps_new_empty_simple ("audio/x-qdm");
14221 _codec ("QDesign Music v.2");
14222 /* FIXME: QDesign music version 2 (no constant) */
14223 if (FALSE && data) {
14224 caps = gst_caps_new_simple ("audio/x-qdm2",
14225 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
14226 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
14227 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
14229 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
14233 _codec ("GSM audio");
14234 caps = gst_caps_new_empty_simple ("audio/x-gsm");
14237 _codec ("AMR audio");
14238 caps = gst_caps_new_empty_simple ("audio/AMR");
14241 _codec ("AMR-WB audio");
14242 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
14245 _codec ("Quicktime IMA ADPCM");
14246 caps = gst_caps_new_simple ("audio/x-adpcm",
14247 "layout", G_TYPE_STRING, "quicktime", NULL);
14250 _codec ("Apple lossless audio");
14251 caps = gst_caps_new_empty_simple ("audio/x-alac");
14254 _codec ("Free Lossless Audio Codec");
14255 caps = gst_caps_new_simple ("audio/x-flac",
14256 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14258 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
14259 _codec ("QualComm PureVoice");
14260 caps = gst_caps_from_string ("audio/qcelp");
14265 caps = gst_caps_new_empty_simple ("audio/x-wma");
14269 caps = gst_caps_new_empty_simple ("audio/x-opus");
14276 GstAudioFormat format;
14279 FLAG_IS_FLOAT = 0x1,
14280 FLAG_IS_BIG_ENDIAN = 0x2,
14281 FLAG_IS_SIGNED = 0x4,
14282 FLAG_IS_PACKED = 0x8,
14283 FLAG_IS_ALIGNED_HIGH = 0x10,
14284 FLAG_IS_NON_INTERLEAVED = 0x20
14286 _codec ("Raw LPCM audio");
14288 if (data && len >= 36) {
14289 depth = QT_UINT32 (data + 24);
14290 flags = QT_UINT32 (data + 28);
14291 width = QT_UINT32 (data + 32) * 8 / entry->n_channels;
14293 if ((flags & FLAG_IS_FLOAT) == 0) {
14298 if ((flags & FLAG_IS_ALIGNED_HIGH))
14301 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
14302 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
14303 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
14304 caps = gst_caps_new_simple ("audio/x-raw",
14305 "format", G_TYPE_STRING,
14307 GST_AUDIO_FORMAT_UNKNOWN ? gst_audio_format_to_string (format) :
14308 "UNKNOWN", "layout", G_TYPE_STRING,
14309 (flags & FLAG_IS_NON_INTERLEAVED) ? "non-interleaved" :
14310 "interleaved", NULL);
14311 stream->alignment = GST_ROUND_UP_8 (depth);
14312 stream->alignment = round_up_pow2 (stream->alignment);
14317 if (flags & FLAG_IS_BIG_ENDIAN)
14318 format = GST_AUDIO_FORMAT_F64BE;
14320 format = GST_AUDIO_FORMAT_F64LE;
14322 if (flags & FLAG_IS_BIG_ENDIAN)
14323 format = GST_AUDIO_FORMAT_F32BE;
14325 format = GST_AUDIO_FORMAT_F32LE;
14327 caps = gst_caps_new_simple ("audio/x-raw",
14328 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14329 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
14330 "non-interleaved" : "interleaved", NULL);
14331 stream->alignment = width / 8;
14335 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
14339 caps = _get_unknown_codec_name ("audio", fourcc);
14345 GstCaps *templ_caps =
14346 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
14347 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
14348 gst_caps_unref (caps);
14349 gst_caps_unref (templ_caps);
14350 caps = intersection;
14353 /* enable clipping for raw audio streams */
14354 s = gst_caps_get_structure (caps, 0);
14355 name = gst_structure_get_name (s);
14356 if (g_str_has_prefix (name, "audio/x-raw")) {
14357 stream->need_clip = TRUE;
14358 stream->max_buffer_size = 4096 * entry->bytes_per_frame;
14359 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
14365 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14366 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14367 const guint8 * stsd_entry_data, gchar ** codec_name)
14371 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14375 _codec ("DVD subtitle");
14376 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
14377 stream->need_process = TRUE;
14380 _codec ("Quicktime timed text");
14383 _codec ("3GPP timed text");
14385 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
14387 /* actual text piece needs to be extracted */
14388 stream->need_process = TRUE;
14391 _codec ("XML subtitles");
14392 caps = gst_caps_new_empty_simple ("application/ttml+xml");
14396 caps = _get_unknown_codec_name ("text", fourcc);
14404 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14405 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14406 const guint8 * stsd_entry_data, gchar ** codec_name)
14412 _codec ("MPEG 1 video");
14413 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14414 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14424 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
14425 const gchar * system_id)
14429 if (!qtdemux->protection_system_ids)
14430 qtdemux->protection_system_ids =
14431 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
14432 /* Check whether we already have an entry for this system ID. */
14433 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
14434 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
14435 if (g_ascii_strcasecmp (system_id, id) == 0) {
14439 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
14440 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,