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;
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 ();
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);
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);
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 = 0;
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)
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_free (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 gst_tag_list_unref (stream->stream_tags);
2547 gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
2548 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, stream->pad);
2550 g_free (stream->stsd_entries);
2555 gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int i)
2557 g_assert (i >= 0 && i < qtdemux->n_streams && qtdemux->streams[i] != NULL);
2559 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[i]);
2560 qtdemux->streams[i] = qtdemux->streams[qtdemux->n_streams - 1];
2561 qtdemux->streams[qtdemux->n_streams - 1] = NULL;
2562 qtdemux->n_streams--;
2565 static GstStateChangeReturn
2566 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2568 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2569 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2571 switch (transition) {
2572 case GST_STATE_CHANGE_PAUSED_TO_READY:
2578 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2580 switch (transition) {
2581 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2582 gst_qtdemux_reset (qtdemux, TRUE);
2593 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2595 /* counts as header data */
2596 qtdemux->header_size += length;
2598 /* only consider at least a sufficiently complete ftyp atom */
2602 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2603 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2604 GST_FOURCC_ARGS (qtdemux->major_brand));
2605 if (qtdemux->comp_brands)
2606 gst_buffer_unref (qtdemux->comp_brands);
2607 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2608 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2613 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist,
2614 GstTagList * xmptaglist)
2616 /* Strip out bogus fields */
2618 if (gst_tag_list_get_scope (taglist) == GST_TAG_SCOPE_GLOBAL) {
2619 gst_tag_list_remove_tag (xmptaglist, GST_TAG_VIDEO_CODEC);
2620 gst_tag_list_remove_tag (xmptaglist, GST_TAG_AUDIO_CODEC);
2622 gst_tag_list_remove_tag (xmptaglist, GST_TAG_CONTAINER_FORMAT);
2625 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, xmptaglist);
2627 /* prioritize native tags using _KEEP mode */
2628 gst_tag_list_insert (taglist, xmptaglist, GST_TAG_MERGE_KEEP);
2629 gst_tag_list_unref (xmptaglist);
2634 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
2642 QtDemuxStream *stream;
2643 GstStructure *structure;
2644 QtDemuxCencSampleSetInfo *ss_info = NULL;
2645 const gchar *system_id;
2646 gboolean uses_sub_sample_encryption = FALSE;
2648 if (qtdemux->n_streams == 0)
2651 stream = qtdemux->streams[0];
2653 structure = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
2654 if (!gst_structure_has_name (structure, "application/x-cenc")) {
2655 GST_WARNING_OBJECT (qtdemux,
2656 "Attempting PIFF box parsing on an unencrypted stream.");
2660 gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
2661 G_TYPE_STRING, &system_id, NULL);
2662 gst_qtdemux_append_protection_system_id (qtdemux, system_id);
2664 stream->protected = TRUE;
2665 stream->protection_scheme_type = FOURCC_cenc;
2667 if (!stream->protection_scheme_info)
2668 stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
2670 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2672 if (ss_info->default_properties)
2673 gst_structure_free (ss_info->default_properties);
2675 ss_info->default_properties =
2676 gst_structure_new ("application/x-cenc",
2677 "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE, NULL);
2679 if (ss_info->crypto_info) {
2680 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
2681 g_ptr_array_free (ss_info->crypto_info, TRUE);
2682 ss_info->crypto_info = NULL;
2686 gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
2688 if (!gst_byte_reader_get_uint8 (&br, &version)) {
2689 GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
2693 if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
2694 GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
2698 if ((flags & 0x000001)) {
2699 guint32 algorithm_id = 0;
2702 gboolean is_encrypted = TRUE;
2704 if (!gst_byte_reader_get_uint24_le (&br, &algorithm_id)) {
2705 GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
2710 if (algorithm_id == 0) {
2711 is_encrypted = FALSE;
2712 } else if (algorithm_id == 1) {
2713 /* FIXME: maybe store this in properties? */
2714 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
2715 } else if (algorithm_id == 2) {
2716 /* FIXME: maybe store this in properties? */
2717 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
2720 if (!gst_byte_reader_get_uint8 (&br, &iv_size))
2723 if (!gst_byte_reader_get_data (&br, 16, &kid))
2726 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
2727 gst_buffer_fill (kid_buf, 0, kid, 16);
2728 if (ss_info->default_properties)
2729 gst_structure_free (ss_info->default_properties);
2730 ss_info->default_properties =
2731 gst_structure_new ("application/x-cenc",
2732 "iv_size", G_TYPE_UINT, iv_size,
2733 "encrypted", G_TYPE_BOOLEAN, is_encrypted,
2734 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
2735 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
2736 "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
2737 gst_buffer_unref (kid_buf);
2738 } else if ((flags & 0x000002)) {
2739 uses_sub_sample_encryption = TRUE;
2742 if (!gst_byte_reader_get_uint32_be (&br, &qtdemux->cenc_aux_sample_count)) {
2743 GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
2747 ss_info->crypto_info =
2748 g_ptr_array_new_full (qtdemux->cenc_aux_sample_count,
2749 (GDestroyNotify) qtdemux_gst_structure_free);
2751 for (i = 0; i < qtdemux->cenc_aux_sample_count; ++i) {
2752 GstStructure *properties;
2756 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
2757 if (properties == NULL) {
2758 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
2762 if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
2763 GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
2764 gst_structure_free (properties);
2767 buf = gst_buffer_new_wrapped (data, iv_size);
2768 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
2769 gst_buffer_unref (buf);
2771 if (uses_sub_sample_encryption) {
2772 guint16 n_subsamples;
2774 if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
2775 || n_subsamples == 0) {
2776 GST_ERROR_OBJECT (qtdemux,
2777 "failed to get subsample count for sample %u", i);
2778 gst_structure_free (properties);
2781 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
2782 if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
2783 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
2785 gst_structure_free (properties);
2788 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
2789 gst_structure_set (properties,
2790 "subsample_count", G_TYPE_UINT, n_subsamples,
2791 "subsamples", GST_TYPE_BUFFER, buf, NULL);
2792 gst_buffer_unref (buf);
2794 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
2797 g_ptr_array_add (ss_info->crypto_info, properties);
2802 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2804 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2805 0x97, 0xA9, 0x42, 0xE8,
2806 0x9C, 0x71, 0x99, 0x94,
2807 0x91, 0xE3, 0xAF, 0xAC
2809 static const guint8 playready_uuid[] = {
2810 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2811 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2814 static const guint8 piff_sample_encryption_uuid[] = {
2815 0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
2816 0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
2821 /* counts as header data */
2822 qtdemux->header_size += length;
2824 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2826 if (length <= offset + 16) {
2827 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2831 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2833 GstTagList *taglist;
2835 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2836 length - offset - 16, NULL);
2837 taglist = gst_tag_list_from_xmp_buffer (buf);
2838 gst_buffer_unref (buf);
2840 /* make sure we have a usable taglist */
2841 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
2843 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
2845 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
2847 const gunichar2 *s_utf16;
2850 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
2851 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
2852 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
2853 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
2857 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
2858 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
2860 } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
2861 qtdemux_parse_piff (qtdemux, buffer, length, offset);
2863 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
2864 GST_READ_UINT32_LE (buffer + offset),
2865 GST_READ_UINT32_LE (buffer + offset + 4),
2866 GST_READ_UINT32_LE (buffer + offset + 8),
2867 GST_READ_UINT32_LE (buffer + offset + 12));
2872 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2874 GstSidxParser sidx_parser;
2875 GstIsoffParserResult res;
2878 gst_isoff_qt_sidx_parser_init (&sidx_parser);
2881 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
2883 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
2884 if (res == GST_ISOFF_QT_PARSER_DONE) {
2885 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
2887 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
2890 /* caller verifies at least 8 bytes in buf */
2892 extract_initial_length_and_fourcc (const guint8 * data, guint size,
2893 guint64 * plength, guint32 * pfourcc)
2898 length = QT_UINT32 (data);
2899 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2900 fourcc = QT_FOURCC (data + 4);
2901 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
2904 length = G_MAXUINT64;
2905 } else if (length == 1 && size >= 16) {
2906 /* this means we have an extended size, which is the 64 bit value of
2907 * the next 8 bytes */
2908 length = QT_UINT64 (data + 8);
2909 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2919 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
2921 guint32 version = 0;
2922 GstClockTime duration = 0;
2924 if (!gst_byte_reader_get_uint32_be (br, &version))
2929 if (!gst_byte_reader_get_uint64_be (br, &duration))
2934 if (!gst_byte_reader_get_uint32_be (br, &dur))
2939 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
2940 qtdemux->duration = duration;
2946 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
2952 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
2953 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
2955 if (!stream->parsed_trex && qtdemux->moov_node) {
2957 GstByteReader trex_data;
2959 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
2961 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
2964 guint32 id = 0, sdi = 0, dur = 0, size = 0, flags = 0;
2966 /* skip version/flags */
2967 if (!gst_byte_reader_skip (&trex_data, 4))
2969 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
2971 if (id != stream->track_id)
2973 if (!gst_byte_reader_get_uint32_be (&trex_data, &sdi))
2975 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2977 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
2979 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
2982 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
2983 "duration %d, size %d, flags 0x%x", stream->track_id,
2986 stream->parsed_trex = TRUE;
2987 stream->def_sample_description_index = sdi;
2988 stream->def_sample_duration = dur;
2989 stream->def_sample_size = size;
2990 stream->def_sample_flags = flags;
2993 /* iterate all siblings */
2994 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
3000 *ds_duration = stream->def_sample_duration;
3001 *ds_size = stream->def_sample_size;
3002 *ds_flags = stream->def_sample_flags;
3004 /* even then, above values are better than random ... */
3005 if (G_UNLIKELY (!stream->parsed_trex)) {
3006 GST_WARNING_OBJECT (qtdemux,
3007 "failed to find fragment defaults for stream %d", stream->track_id);
3014 /* This method should be called whenever a more accurate duration might
3015 * have been found. It will update all relevant variables if/where needed
3018 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
3022 GstClockTime prevdur;
3024 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
3026 if (movdur > qtdemux->duration) {
3027 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
3028 GST_DEBUG_OBJECT (qtdemux,
3029 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
3030 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
3031 qtdemux->duration = movdur;
3032 GST_DEBUG_OBJECT (qtdemux,
3033 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
3034 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
3035 GST_TIME_ARGS (qtdemux->segment.stop));
3036 if (qtdemux->segment.duration == prevdur) {
3037 /* If the current segment has duration/stop identical to previous duration
3038 * update them also (because they were set at that point in time with
3039 * the wrong duration */
3040 /* We convert the value *from* the timescale version to avoid rounding errors */
3041 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
3042 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
3043 qtdemux->segment.duration = fixeddur;
3044 qtdemux->segment.stop = fixeddur;
3047 for (i = 0; i < qtdemux->n_streams; i++) {
3048 QtDemuxStream *stream = qtdemux->streams[i];
3050 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
3051 if (movdur > stream->duration) {
3052 GST_DEBUG_OBJECT (qtdemux,
3053 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
3054 GST_TIME_ARGS (duration));
3055 stream->duration = movdur;
3056 /* internal duration tracking state has been updated above, so */
3057 /* preserve an open-ended dummy segment rather than repeatedly updating
3058 * it and spamming downstream accordingly with segment events */
3059 if (stream->dummy_segment &&
3060 GST_CLOCK_TIME_IS_VALID (stream->segments[0].duration)) {
3061 /* Update all dummy values to new duration */
3062 stream->segments[0].stop_time = duration;
3063 stream->segments[0].duration = duration;
3064 stream->segments[0].media_stop = duration;
3066 /* let downstream know we possibly have a new stop time */
3067 if (stream->segment_index != -1) {
3070 if (qtdemux->segment.rate >= 0) {
3071 pos = stream->segment.start;
3073 pos = stream->segment.stop;
3076 gst_qtdemux_stream_update_segment (qtdemux, stream,
3077 stream->segment_index, pos, NULL, NULL);
3086 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
3087 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
3088 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
3089 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts,
3092 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
3094 gint32 data_offset = 0;
3095 guint32 flags = 0, first_flags = 0, samples_count = 0;
3098 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
3099 QtDemuxSample *sample;
3100 gboolean ismv = FALSE;
3101 gint64 initial_offset;
3103 GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
3104 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
3105 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
3106 d_sample_size, d_sample_flags, *base_offset, decode_ts);
3108 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
3109 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
3113 /* presence of stss or not can't really tell us much,
3114 * and flags and so on tend to be marginally reliable in these files */
3115 if (stream->subtype == FOURCC_soun) {
3116 GST_DEBUG_OBJECT (qtdemux,
3117 "sound track in fragmented file; marking all keyframes");
3118 stream->all_keyframe = TRUE;
3121 if (!gst_byte_reader_skip (trun, 1) ||
3122 !gst_byte_reader_get_uint24_be (trun, &flags))
3125 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3128 if (flags & TR_DATA_OFFSET) {
3129 /* note this is really signed */
3130 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3132 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3133 /* default base offset = first byte of moof */
3134 if (*base_offset == -1) {
3135 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3136 *base_offset = moof_offset;
3138 *running_offset = *base_offset + data_offset;
3140 /* if no offset at all, that would mean data starts at moof start,
3141 * which is a bit wrong and is ismv crappy way, so compensate
3142 * assuming data is in mdat following moof */
3143 if (*base_offset == -1) {
3144 *base_offset = moof_offset + moof_length + 8;
3145 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3148 if (*running_offset == -1)
3149 *running_offset = *base_offset;
3152 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3154 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3155 data_offset, flags, samples_count);
3157 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3158 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3159 GST_DEBUG_OBJECT (qtdemux,
3160 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3161 flags ^= TR_FIRST_SAMPLE_FLAGS;
3163 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3165 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3169 /* FIXME ? spec says other bits should also be checked to determine
3170 * entry size (and prefix size for that matter) */
3172 dur_offset = size_offset = 0;
3173 if (flags & TR_SAMPLE_DURATION) {
3174 GST_LOG_OBJECT (qtdemux, "entry duration present");
3175 dur_offset = entry_size;
3178 if (flags & TR_SAMPLE_SIZE) {
3179 GST_LOG_OBJECT (qtdemux, "entry size present");
3180 size_offset = entry_size;
3183 if (flags & TR_SAMPLE_FLAGS) {
3184 GST_LOG_OBJECT (qtdemux, "entry flags present");
3185 flags_offset = entry_size;
3188 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3189 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3190 ct_offset = entry_size;
3194 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3196 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3198 if (stream->n_samples + samples_count >=
3199 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3202 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3203 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3204 (stream->n_samples + samples_count) *
3205 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3207 /* create a new array of samples if it's the first sample parsed */
3208 if (stream->n_samples == 0) {
3209 g_assert (stream->samples == NULL);
3210 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3211 /* or try to reallocate it with space enough to insert the new samples */
3213 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3214 stream->n_samples + samples_count);
3215 if (stream->samples == NULL)
3218 if (qtdemux->fragment_start != -1) {
3219 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3220 qtdemux->fragment_start = -1;
3222 if (stream->n_samples == 0) {
3223 if (decode_ts > 0) {
3224 timestamp = decode_ts;
3225 } else if (stream->pending_seek != NULL) {
3226 /* if we don't have a timestamp from a tfdt box, we'll use the one
3227 * from the mfra seek table */
3228 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3229 GST_TIME_ARGS (stream->pending_seek->ts));
3231 /* FIXME: this is not fully correct, the timestamp refers to the random
3232 * access sample refered to in the tfra entry, which may not necessarily
3233 * be the first sample in the tfrag/trun (but hopefully/usually is) */
3234 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3239 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3240 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3241 GST_TIME_ARGS (gst_ts));
3243 /* subsequent fragments extend stream */
3245 stream->samples[stream->n_samples - 1].timestamp +
3246 stream->samples[stream->n_samples - 1].duration;
3248 /* If this is a GST_FORMAT_BYTES stream and there's a significant
3249 * difference (1 sec.) between decode_ts and timestamp, prefer the
3251 if (has_tfdt && !qtdemux->upstream_format_is_time
3252 && ABSDIFF (decode_ts, timestamp) >
3253 MAX (stream->duration_last_moof / 2,
3254 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) {
3255 GST_INFO_OBJECT (qtdemux,
3256 "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT
3257 ") are significantly different (more than %" GST_TIME_FORMAT
3258 "), using decode_ts",
3259 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)),
3260 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)),
3261 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
3262 MAX (stream->duration_last_moof / 2,
3263 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND)))));
3264 timestamp = decode_ts;
3267 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3268 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3269 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3273 initial_offset = *running_offset;
3275 sample = stream->samples + stream->n_samples;
3276 for (i = 0; i < samples_count; i++) {
3277 guint32 dur, size, sflags, ct;
3279 /* first read sample data */
3280 if (flags & TR_SAMPLE_DURATION) {
3281 dur = QT_UINT32 (data + dur_offset);
3283 dur = d_sample_duration;
3285 if (flags & TR_SAMPLE_SIZE) {
3286 size = QT_UINT32 (data + size_offset);
3288 size = d_sample_size;
3290 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3292 sflags = first_flags;
3294 sflags = d_sample_flags;
3296 } else if (flags & TR_SAMPLE_FLAGS) {
3297 sflags = QT_UINT32 (data + flags_offset);
3299 sflags = d_sample_flags;
3301 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3302 ct = QT_UINT32 (data + ct_offset);
3308 /* fill the sample information */
3309 sample->offset = *running_offset;
3310 sample->pts_offset = ct;
3311 sample->size = size;
3312 sample->timestamp = timestamp;
3313 sample->duration = dur;
3314 /* sample-is-difference-sample */
3315 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3316 * now idea how it relates to bitfield other than massive LE/BE confusion */
3317 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3318 *running_offset += size;
3320 stream->duration_moof += dur;
3324 /* Update total duration if needed */
3325 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3327 /* Pre-emptively figure out size of mdat based on trun information.
3328 * If the [mdat] atom is effectivelly read, it will be replaced by the actual
3329 * size, else we will still be able to use this when dealing with gap'ed
3331 qtdemux->mdatleft = *running_offset - initial_offset;
3332 qtdemux->mdatoffset = initial_offset;
3333 qtdemux->mdatsize = qtdemux->mdatleft;
3335 stream->n_samples += samples_count;
3336 stream->n_samples_moof += samples_count;
3338 if (stream->pending_seek != NULL)
3339 stream->pending_seek = NULL;
3345 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3350 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3356 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3357 "be larger than %uMB (broken file?)", stream->n_samples,
3358 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3363 /* find stream with @id */
3364 static inline QtDemuxStream *
3365 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3367 QtDemuxStream *stream;
3371 if (G_UNLIKELY (!id)) {
3372 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3376 /* try to get it fast and simple */
3377 if (G_LIKELY (id <= qtdemux->n_streams)) {
3378 stream = qtdemux->streams[id - 1];
3379 if (G_LIKELY (stream->track_id == id))
3383 /* linear search otherwise */
3384 for (i = 0; i < qtdemux->n_streams; i++) {
3385 stream = qtdemux->streams[i];
3386 if (stream->track_id == id)
3389 if (qtdemux->mss_mode) {
3390 /* mss should have only 1 stream anyway */
3391 return qtdemux->streams[0];
3398 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3399 guint32 * fragment_number)
3401 if (!gst_byte_reader_skip (mfhd, 4))
3403 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3408 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3414 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3415 QtDemuxStream ** stream, guint32 * default_sample_duration,
3416 guint32 * default_sample_size, guint32 * default_sample_flags,
3417 gint64 * base_offset)
3420 guint32 track_id = 0;
3422 if (!gst_byte_reader_skip (tfhd, 1) ||
3423 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3426 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3429 *stream = qtdemux_find_stream (qtdemux, track_id);
3430 if (G_UNLIKELY (!*stream))
3431 goto unknown_stream;
3433 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3434 *base_offset = qtdemux->moof_offset;
3436 if (flags & TF_BASE_DATA_OFFSET)
3437 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3440 /* obtain stream defaults */
3441 qtdemux_parse_trex (qtdemux, *stream,
3442 default_sample_duration, default_sample_size, default_sample_flags);
3444 (*stream)->stsd_sample_description_id =
3445 (*stream)->def_sample_description_index - 1;
3447 if (flags & TF_SAMPLE_DESCRIPTION_INDEX) {
3448 guint32 sample_description_index;
3449 if (!gst_byte_reader_get_uint32_be (tfhd, &sample_description_index))
3451 (*stream)->stsd_sample_description_id = sample_description_index - 1;
3454 if (qtdemux->mss_mode) {
3455 /* mss has no stsd entry */
3456 (*stream)->stsd_sample_description_id = 0;
3459 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3460 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3463 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3464 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3467 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3468 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3475 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3480 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
3486 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3487 guint64 * decode_time)
3489 guint32 version = 0;
3491 if (!gst_byte_reader_get_uint32_be (br, &version))
3496 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3499 guint32 dec_time = 0;
3500 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3502 *decode_time = dec_time;
3505 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3512 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3517 /* Returns a pointer to a GstStructure containing the properties of
3518 * the stream sample identified by @sample_index. The caller must unref
3519 * the returned object after use. Returns NULL if unsuccessful. */
3520 static GstStructure *
3521 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3522 QtDemuxStream * stream, guint sample_index)
3524 QtDemuxCencSampleSetInfo *info = NULL;
3526 g_return_val_if_fail (stream != NULL, NULL);
3527 g_return_val_if_fail (stream->protected, NULL);
3528 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3530 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3532 /* Currently, cenc properties for groups of samples are not supported, so
3533 * simply return a copy of the default sample properties */
3534 return gst_structure_copy (info->default_properties);
3537 /* Parses the sizes of sample auxiliary information contained within a stream,
3538 * as given in a saiz box. Returns array of sample_count guint8 size values,
3539 * or NULL on failure */
3541 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3542 GstByteReader * br, guint32 * sample_count)
3546 guint8 default_info_size;
3548 g_return_val_if_fail (qtdemux != NULL, NULL);
3549 g_return_val_if_fail (stream != NULL, NULL);
3550 g_return_val_if_fail (br != NULL, NULL);
3551 g_return_val_if_fail (sample_count != NULL, NULL);
3553 if (!gst_byte_reader_get_uint32_be (br, &flags))
3557 /* aux_info_type and aux_info_type_parameter are ignored */
3558 if (!gst_byte_reader_skip (br, 8))
3562 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3564 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3566 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3568 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3571 if (default_info_size == 0) {
3572 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3576 info_sizes = g_new (guint8, *sample_count);
3577 memset (info_sizes, default_info_size, *sample_count);
3583 /* Parses the offset of sample auxiliary information contained within a stream,
3584 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3586 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3587 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3592 guint32 aux_info_type = 0;
3593 guint32 aux_info_type_parameter = 0;
3594 guint32 entry_count;
3597 const guint8 *aux_info_type_data = NULL;
3599 g_return_val_if_fail (qtdemux != NULL, FALSE);
3600 g_return_val_if_fail (stream != NULL, FALSE);
3601 g_return_val_if_fail (br != NULL, FALSE);
3602 g_return_val_if_fail (offset != NULL, FALSE);
3604 if (!gst_byte_reader_get_uint8 (br, &version))
3607 if (!gst_byte_reader_get_uint24_be (br, &flags))
3612 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3614 aux_info_type = QT_FOURCC (aux_info_type_data);
3616 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3618 } else if (stream->protected) {
3619 aux_info_type = stream->protection_scheme_type;
3621 aux_info_type = CUR_STREAM (stream)->fourcc;
3625 *info_type = aux_info_type;
3626 if (info_type_parameter)
3627 *info_type_parameter = aux_info_type_parameter;
3629 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3630 "aux_info_type_parameter: %#06x",
3631 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3633 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3636 if (entry_count != 1) {
3637 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3642 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3644 *offset = (guint64) off_32;
3646 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3651 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3656 qtdemux_gst_structure_free (GstStructure * gststructure)
3659 gst_structure_free (gststructure);
3663 /* Parses auxiliary information relating to samples protected using Common
3664 * Encryption (cenc); the format of this information is defined in
3665 * ISO/IEC 23001-7. Returns TRUE if successful; FALSE otherwise. */
3667 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3668 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3670 QtDemuxCencSampleSetInfo *ss_info = NULL;
3673 GPtrArray *old_crypto_info = NULL;
3674 guint old_entries = 0;
3676 g_return_val_if_fail (qtdemux != NULL, FALSE);
3677 g_return_val_if_fail (stream != NULL, FALSE);
3678 g_return_val_if_fail (br != NULL, FALSE);
3679 g_return_val_if_fail (stream->protected, FALSE);
3680 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3682 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3684 if (ss_info->crypto_info) {
3685 old_crypto_info = ss_info->crypto_info;
3686 /* Count number of non-null entries remaining at the tail end */
3687 for (i = old_crypto_info->len - 1; i >= 0; i--) {
3688 if (g_ptr_array_index (old_crypto_info, i) == NULL)
3694 ss_info->crypto_info =
3695 g_ptr_array_new_full (sample_count + old_entries,
3696 (GDestroyNotify) qtdemux_gst_structure_free);
3698 /* We preserve old entries because we parse the next moof in advance
3699 * of consuming all samples from the previous moof, and otherwise
3700 * we'd discard the corresponding crypto info for the samples
3701 * from the previous fragment. */
3703 GST_DEBUG_OBJECT (qtdemux, "Preserving %d old crypto info entries",
3705 for (i = old_crypto_info->len - old_entries; i < old_crypto_info->len; i++) {
3706 g_ptr_array_add (ss_info->crypto_info, g_ptr_array_index (old_crypto_info,
3708 g_ptr_array_index (old_crypto_info, i) = NULL;
3712 if (old_crypto_info) {
3713 /* Everything now belongs to the new array */
3714 g_ptr_array_free (old_crypto_info, TRUE);
3717 for (i = 0; i < sample_count; ++i) {
3718 GstStructure *properties;
3719 guint16 n_subsamples = 0;
3724 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3725 if (properties == NULL) {
3726 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3729 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3730 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3731 gst_structure_free (properties);
3734 if (!gst_byte_reader_dup_data (br, iv_size, &data)) {
3735 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3736 gst_structure_free (properties);
3739 buf = gst_buffer_new_wrapped (data, iv_size);
3740 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3741 gst_buffer_unref (buf);
3742 size = info_sizes[i];
3743 if (size > iv_size) {
3744 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3745 || !(n_subsamples > 0)) {
3746 gst_structure_free (properties);
3747 GST_ERROR_OBJECT (qtdemux,
3748 "failed to get subsample count for sample %u", i);
3751 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3752 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3753 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3755 gst_structure_free (properties);
3758 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3760 gst_structure_free (properties);
3763 gst_structure_set (properties,
3764 "subsample_count", G_TYPE_UINT, n_subsamples,
3765 "subsamples", GST_TYPE_BUFFER, buf, NULL);
3766 gst_buffer_unref (buf);
3768 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3770 g_ptr_array_add (ss_info->crypto_info, properties);
3775 /* Converts a UUID in raw byte form to a string representation, as defined in
3776 * RFC 4122. The caller takes ownership of the returned string and is
3777 * responsible for freeing it after use. */
3779 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3781 const guint8 *uuid = (const guint8 *) uuid_bytes;
3783 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3784 "%02x%02x-%02x%02x%02x%02x%02x%02x",
3785 uuid[0], uuid[1], uuid[2], uuid[3],
3786 uuid[4], uuid[5], uuid[6], uuid[7],
3787 uuid[8], uuid[9], uuid[10], uuid[11],
3788 uuid[12], uuid[13], uuid[14], uuid[15]);
3791 /* Parses a Protection System Specific Header box (pssh), as defined in the
3792 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3793 * information needed by a specific content protection system in order to
3794 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3797 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
3799 gchar *sysid_string;
3800 guint32 pssh_size = QT_UINT32 (node->data);
3801 GstBuffer *pssh = NULL;
3802 GstEvent *event = NULL;
3803 guint32 parent_box_type;
3806 if (G_UNLIKELY (pssh_size < 32U)) {
3807 GST_ERROR_OBJECT (qtdemux, "invalid box size");
3812 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
3814 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
3816 pssh = gst_buffer_new_wrapped (g_memdup (node->data, pssh_size), pssh_size);
3817 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
3818 gst_buffer_get_size (pssh));
3820 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
3822 /* Push an event containing the pssh box onto the queues of all streams. */
3823 event = gst_event_new_protection (sysid_string, pssh,
3824 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
3825 for (i = 0; i < qtdemux->n_streams; ++i) {
3826 g_queue_push_tail (&qtdemux->streams[i]->protection_scheme_event_queue,
3827 gst_event_ref (event));
3829 g_free (sysid_string);
3830 gst_event_unref (event);
3831 gst_buffer_unref (pssh);
3836 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
3837 guint64 moof_offset, QtDemuxStream * stream)
3839 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
3841 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
3842 GNode *saiz_node, *saio_node, *pssh_node;
3843 GstByteReader saiz_data, saio_data;
3844 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
3845 gint64 base_offset, running_offset;
3848 /* NOTE @stream ignored */
3850 moof_node = g_node_new ((guint8 *) buffer);
3851 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
3852 qtdemux_node_dump (qtdemux, moof_node);
3854 /* Get fragment number from mfhd and check it's valid */
3856 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
3857 if (mfhd_node == NULL)
3859 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
3861 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
3863 /* unknown base_offset to start with */
3864 base_offset = running_offset = -1;
3865 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
3867 guint64 decode_time = 0;
3869 /* Fragment Header node */
3871 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
3875 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
3876 &ds_size, &ds_flags, &base_offset))
3879 /* The following code assumes at most a single set of sample auxiliary
3880 * data in the fragment (consisting of a saiz box and a corresponding saio
3881 * box); in theory, however, there could be multiple sets of sample
3882 * auxiliary data in a fragment. */
3884 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
3887 guint32 info_type = 0;
3889 guint32 info_type_parameter = 0;
3891 g_free (qtdemux->cenc_aux_info_sizes);
3893 qtdemux->cenc_aux_info_sizes =
3894 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
3895 &qtdemux->cenc_aux_sample_count);
3896 if (qtdemux->cenc_aux_info_sizes == NULL) {
3897 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
3901 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
3904 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
3905 g_free (qtdemux->cenc_aux_info_sizes);
3906 qtdemux->cenc_aux_info_sizes = NULL;
3910 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
3911 &info_type, &info_type_parameter, &offset))) {
3912 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
3913 g_free (qtdemux->cenc_aux_info_sizes);
3914 qtdemux->cenc_aux_info_sizes = NULL;
3917 if (base_offset > -1 && base_offset > qtdemux->moof_offset)
3918 offset += (guint64) (base_offset - qtdemux->moof_offset);
3919 if (info_type == FOURCC_cenc && info_type_parameter == 0U) {
3921 if (offset > length) {
3922 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
3923 qtdemux->cenc_aux_info_offset = offset;
3925 gst_byte_reader_init (&br, buffer + offset, length - offset);
3926 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
3927 qtdemux->cenc_aux_info_sizes,
3928 qtdemux->cenc_aux_sample_count)) {
3929 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
3930 g_free (qtdemux->cenc_aux_info_sizes);
3931 qtdemux->cenc_aux_info_sizes = NULL;
3939 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
3942 /* We'll use decode_time to interpolate timestamps
3943 * in case the input timestamps are missing */
3944 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
3946 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
3947 " (%" GST_TIME_FORMAT ")", decode_time,
3948 GST_TIME_ARGS (stream ? QTSTREAMTIME_TO_GSTTIME (stream,
3949 decode_time) : GST_CLOCK_TIME_NONE));
3951 /* Discard the fragment buffer timestamp info to avoid using it.
3952 * Rely on tfdt instead as it is more accurate than the timestamp
3953 * that is fetched from a manifest/playlist and is usually
3955 qtdemux->fragment_start = -1;
3958 if (G_UNLIKELY (!stream)) {
3959 /* we lost track of offset, we'll need to regain it,
3960 * but can delay complaining until later or avoid doing so altogether */
3964 if (G_UNLIKELY (base_offset < -1))
3967 if (qtdemux->upstream_format_is_time)
3968 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
3970 /* initialise moof sample data */
3971 stream->n_samples_moof = 0;
3972 stream->duration_last_moof = stream->duration_moof;
3973 stream->duration_moof = 0;
3975 /* Track Run node */
3977 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
3980 qtdemux_parse_trun (qtdemux, &trun_data, stream,
3981 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
3982 &running_offset, decode_time, (tfdt_node != NULL));
3983 /* iterate all siblings */
3984 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
3988 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
3990 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
3991 guint32 box_length = QT_UINT32 (uuid_buffer);
3993 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
3996 /* if no new base_offset provided for next traf,
3997 * base is end of current traf */
3998 base_offset = running_offset;
3999 running_offset = -1;
4001 if (stream->n_samples_moof && stream->duration_moof)
4002 stream->new_caps = TRUE;
4005 /* iterate all siblings */
4006 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
4009 /* parse any protection system info */
4010 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
4012 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
4013 qtdemux_parse_pssh (qtdemux, pssh_node);
4014 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
4017 g_node_destroy (moof_node);
4022 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
4027 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
4032 GST_DEBUG_OBJECT (qtdemux, "lost offset");
4037 g_node_destroy (moof_node);
4038 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4039 (_("This file is corrupt and cannot be played.")), (NULL));
4045 /* might be used if some day we actually use mfra & co
4046 * for random access to fragments,
4047 * but that will require quite some modifications and much less relying
4048 * on a sample array */
4052 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
4054 QtDemuxStream *stream;
4055 guint32 ver_flags, track_id, len, num_entries, i;
4056 guint value_size, traf_size, trun_size, sample_size;
4057 guint64 time = 0, moof_offset = 0;
4059 GstBuffer *buf = NULL;
4064 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
4066 if (!gst_byte_reader_skip (&tfra, 8))
4069 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
4072 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
4073 || !gst_byte_reader_get_uint32_be (&tfra, &len)
4074 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
4077 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
4079 stream = qtdemux_find_stream (qtdemux, track_id);
4081 goto unknown_trackid;
4083 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
4084 sample_size = (len & 3) + 1;
4085 trun_size = ((len & 12) >> 2) + 1;
4086 traf_size = ((len & 48) >> 4) + 1;
4088 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
4089 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
4091 if (num_entries == 0)
4094 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
4095 value_size + value_size + traf_size + trun_size + sample_size))
4098 g_free (stream->ra_entries);
4099 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
4100 stream->n_ra_entries = num_entries;
4102 for (i = 0; i < num_entries; i++) {
4103 qt_atom_parser_get_offset (&tfra, value_size, &time);
4104 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
4105 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
4106 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
4107 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
4109 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
4111 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
4112 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
4114 stream->ra_entries[i].ts = time;
4115 stream->ra_entries[i].moof_offset = moof_offset;
4117 /* don't want to go through the entire file and read all moofs at startup */
4119 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
4120 if (ret != GST_FLOW_OK)
4122 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
4123 moof_offset, stream);
4124 gst_buffer_unref (buf);
4128 check_update_duration (qtdemux, time);
4135 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
4140 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
4145 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4151 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
4153 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
4154 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
4155 GstBuffer *mfro = NULL, *mfra = NULL;
4157 gboolean ret = FALSE;
4158 GNode *mfra_node, *tfra_node;
4159 guint64 mfra_offset = 0;
4160 guint32 fourcc, mfra_size;
4163 /* query upstream size in bytes */
4164 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4165 goto size_query_failed;
4167 /* mfro box should be at the very end of the file */
4168 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4169 if (flow != GST_FLOW_OK)
4172 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4174 fourcc = QT_FOURCC (mfro_map.data + 4);
4175 if (fourcc != FOURCC_mfro)
4178 GST_INFO_OBJECT (qtdemux, "Found mfro box");
4179 if (mfro_map.size < 16)
4180 goto invalid_mfro_size;
4182 mfra_size = QT_UINT32 (mfro_map.data + 12);
4183 if (mfra_size >= len)
4184 goto invalid_mfra_size;
4186 mfra_offset = len - mfra_size;
4188 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4189 mfra_offset, mfra_size);
4191 /* now get and parse mfra box */
4192 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4193 if (flow != GST_FLOW_OK)
4196 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4198 mfra_node = g_node_new ((guint8 *) mfra_map.data);
4199 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4201 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4204 qtdemux_parse_tfra (qtdemux, tfra_node);
4205 /* iterate all siblings */
4206 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4208 g_node_destroy (mfra_node);
4210 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4216 if (mfro_map.memory != NULL)
4217 gst_buffer_unmap (mfro, &mfro_map);
4218 gst_buffer_unref (mfro);
4221 if (mfra_map.memory != NULL)
4222 gst_buffer_unmap (mfra, &mfra_map);
4223 gst_buffer_unref (mfra);
4230 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4235 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4240 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4245 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4251 add_offset (guint64 offset, guint64 advance)
4253 /* Avoid 64-bit overflow by clamping */
4254 if (offset > G_MAXUINT64 - advance)
4256 return offset + advance;
4259 static GstFlowReturn
4260 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4264 GstBuffer *buf = NULL;
4265 GstFlowReturn ret = GST_FLOW_OK;
4266 guint64 cur_offset = qtdemux->offset;
4269 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4270 if (G_UNLIKELY (ret != GST_FLOW_OK))
4272 gst_buffer_map (buf, &map, GST_MAP_READ);
4273 if (G_LIKELY (map.size >= 8))
4274 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4275 gst_buffer_unmap (buf, &map);
4276 gst_buffer_unref (buf);
4278 /* maybe we already got most we needed, so only consider this eof */
4279 if (G_UNLIKELY (length == 0)) {
4280 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4281 (_("Invalid atom size.")),
4282 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4283 GST_FOURCC_ARGS (fourcc)));
4290 /* record for later parsing when needed */
4291 if (!qtdemux->moof_offset) {
4292 qtdemux->moof_offset = qtdemux->offset;
4294 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4297 qtdemux->offset += length; /* skip moof and keep going */
4299 if (qtdemux->got_moov) {
4300 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4312 GST_LOG_OBJECT (qtdemux,
4313 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4314 GST_FOURCC_ARGS (fourcc), cur_offset);
4315 qtdemux->offset = add_offset (qtdemux->offset, length);
4320 GstBuffer *moov = NULL;
4322 if (qtdemux->got_moov) {
4323 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4324 qtdemux->offset = add_offset (qtdemux->offset, length);
4328 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4329 if (ret != GST_FLOW_OK)
4331 gst_buffer_map (moov, &map, GST_MAP_READ);
4333 if (length != map.size) {
4334 /* Some files have a 'moov' atom at the end of the file which contains
4335 * a terminal 'free' atom where the body of the atom is missing.
4336 * Check for, and permit, this special case.
4338 if (map.size >= 8) {
4339 guint8 *final_data = map.data + (map.size - 8);
4340 guint32 final_length = QT_UINT32 (final_data);
4341 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4343 if (final_fourcc == FOURCC_free
4344 && map.size + final_length - 8 == length) {
4345 /* Ok, we've found that special case. Allocate a new buffer with
4346 * that free atom actually present. */
4347 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4348 gst_buffer_fill (newmoov, 0, map.data, map.size);
4349 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4350 gst_buffer_unmap (moov, &map);
4351 gst_buffer_unref (moov);
4353 gst_buffer_map (moov, &map, GST_MAP_READ);
4358 if (length != map.size) {
4359 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4360 (_("This file is incomplete and cannot be played.")),
4361 ("We got less than expected (received %" G_GSIZE_FORMAT
4362 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4363 (guint) length, cur_offset));
4364 gst_buffer_unmap (moov, &map);
4365 gst_buffer_unref (moov);
4366 ret = GST_FLOW_ERROR;
4369 qtdemux->offset += length;
4371 qtdemux_parse_moov (qtdemux, map.data, length);
4372 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4374 qtdemux_parse_tree (qtdemux);
4375 if (qtdemux->moov_node_compressed) {
4376 g_node_destroy (qtdemux->moov_node_compressed);
4377 g_free (qtdemux->moov_node->data);
4379 qtdemux->moov_node_compressed = NULL;
4380 g_node_destroy (qtdemux->moov_node);
4381 qtdemux->moov_node = NULL;
4382 gst_buffer_unmap (moov, &map);
4383 gst_buffer_unref (moov);
4384 qtdemux->got_moov = TRUE;
4390 GstBuffer *ftyp = NULL;
4392 /* extract major brand; might come in handy for ISO vs QT issues */
4393 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4394 if (ret != GST_FLOW_OK)
4396 qtdemux->offset += length;
4397 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4398 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4399 gst_buffer_unmap (ftyp, &map);
4400 gst_buffer_unref (ftyp);
4405 GstBuffer *uuid = NULL;
4407 /* uuid are extension atoms */
4408 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4409 if (ret != GST_FLOW_OK)
4411 qtdemux->offset += length;
4412 gst_buffer_map (uuid, &map, GST_MAP_READ);
4413 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4414 gst_buffer_unmap (uuid, &map);
4415 gst_buffer_unref (uuid);
4420 GstBuffer *sidx = NULL;
4421 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4422 if (ret != GST_FLOW_OK)
4424 qtdemux->offset += length;
4425 gst_buffer_map (sidx, &map, GST_MAP_READ);
4426 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4427 gst_buffer_unmap (sidx, &map);
4428 gst_buffer_unref (sidx);
4433 GstBuffer *unknown = NULL;
4435 GST_LOG_OBJECT (qtdemux,
4436 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4437 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4439 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4440 if (ret != GST_FLOW_OK)
4442 gst_buffer_map (unknown, &map, GST_MAP_READ);
4443 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4444 gst_buffer_unmap (unknown, &map);
4445 gst_buffer_unref (unknown);
4446 qtdemux->offset += length;
4452 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4453 /* digested all data, show what we have */
4454 qtdemux_prepare_streams (qtdemux);
4455 ret = qtdemux_expose_streams (qtdemux);
4457 qtdemux->state = QTDEMUX_STATE_MOVIE;
4458 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4465 /* Seeks to the previous keyframe of the indexed stream and
4466 * aligns other streams with respect to the keyframe timestamp
4467 * of indexed stream. Only called in case of Reverse Playback
4469 static GstFlowReturn
4470 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4473 guint32 seg_idx = 0, k_index = 0;
4474 guint32 ref_seg_idx, ref_k_index;
4475 GstClockTime k_pos = 0, last_stop = 0;
4476 QtDemuxSegment *seg = NULL;
4477 QtDemuxStream *ref_str = NULL;
4478 guint64 seg_media_start_mov; /* segment media start time in mov format */
4481 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4482 * and finally align all the other streams on that timestamp with their
4483 * respective keyframes */
4484 for (n = 0; n < qtdemux->n_streams; n++) {
4485 QtDemuxStream *str = qtdemux->streams[n];
4487 /* No candidate yet, take the first stream */
4493 /* So that stream has a segment, we prefer video streams */
4494 if (str->subtype == FOURCC_vide) {
4500 if (G_UNLIKELY (!ref_str)) {
4501 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4505 if (G_UNLIKELY (!ref_str->from_sample)) {
4506 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4510 /* So that stream has been playing from from_sample to to_sample. We will
4511 * get the timestamp of the previous sample and search for a keyframe before
4512 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4513 if (ref_str->subtype == FOURCC_vide) {
4514 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4515 ref_str->from_sample - 1, FALSE);
4517 if (ref_str->from_sample >= 10)
4518 k_index = ref_str->from_sample - 10;
4524 ref_str->samples[k_index].timestamp +
4525 ref_str->samples[k_index].pts_offset;
4527 /* get current segment for that stream */
4528 seg = &ref_str->segments[ref_str->segment_index];
4529 /* Use segment start in original timescale for comparisons */
4530 seg_media_start_mov = seg->trak_media_start;
4532 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4533 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT "\n",
4534 k_index, target_ts, seg_media_start_mov,
4535 GST_TIME_ARGS (seg->media_start));
4537 /* Crawl back through segments to find the one containing this I frame */
4538 while (target_ts < seg_media_start_mov) {
4539 GST_DEBUG_OBJECT (qtdemux,
4540 "keyframe position (sample %u) is out of segment %u " " target %"
4541 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4542 ref_str->segment_index, target_ts, seg_media_start_mov);
4544 if (G_UNLIKELY (!ref_str->segment_index)) {
4545 /* Reached first segment, let's consider it's EOS */
4548 ref_str->segment_index--;
4549 seg = &ref_str->segments[ref_str->segment_index];
4550 /* Use segment start in original timescale for comparisons */
4551 seg_media_start_mov = seg->trak_media_start;
4553 /* Calculate time position of the keyframe and where we should stop */
4555 QTSTREAMTIME_TO_GSTTIME (ref_str,
4556 target_ts - seg->trak_media_start) + seg->time;
4558 QTSTREAMTIME_TO_GSTTIME (ref_str,
4559 ref_str->samples[ref_str->from_sample].timestamp -
4560 seg->trak_media_start) + seg->time;
4562 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4563 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4564 k_index, GST_TIME_ARGS (k_pos));
4566 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4567 qtdemux->segment.position = last_stop;
4568 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4569 GST_TIME_ARGS (last_stop));
4571 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4572 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4576 ref_seg_idx = ref_str->segment_index;
4577 ref_k_index = k_index;
4579 /* Align them all on this */
4580 for (n = 0; n < qtdemux->n_streams; n++) {
4582 GstClockTime seg_time = 0;
4583 QtDemuxStream *str = qtdemux->streams[n];
4585 /* aligning reference stream again might lead to backing up to yet another
4586 * keyframe (due to timestamp rounding issues),
4587 * potentially putting more load on downstream; so let's try to avoid */
4588 if (str == ref_str) {
4589 seg_idx = ref_seg_idx;
4590 seg = &str->segments[seg_idx];
4591 k_index = ref_k_index;
4592 GST_DEBUG_OBJECT (qtdemux, "reference stream %d segment %d, "
4593 "sample at index %d", n, ref_str->segment_index, k_index);
4595 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4596 GST_DEBUG_OBJECT (qtdemux,
4597 "stream %d align segment %d for keyframe pos %" GST_TIME_FORMAT, n,
4598 seg_idx, GST_TIME_ARGS (k_pos));
4600 /* get segment and time in the segment */
4601 seg = &str->segments[seg_idx];
4602 seg_time = k_pos - seg->time;
4604 /* get the media time in the segment.
4605 * No adjustment for empty "filler" segments */
4606 if (seg->media_start != GST_CLOCK_TIME_NONE)
4607 seg_time += seg->media_start;
4609 /* get the index of the sample with media time */
4610 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4611 GST_DEBUG_OBJECT (qtdemux,
4612 "stream %d sample for %" GST_TIME_FORMAT " at %u", n,
4613 GST_TIME_ARGS (seg_time), index);
4615 /* find previous keyframe */
4616 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
4619 /* Remember until where we want to go */
4620 str->to_sample = str->from_sample - 1;
4621 /* Define our time position */
4623 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4624 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4625 if (seg->media_start != GST_CLOCK_TIME_NONE)
4626 str->time_position -= seg->media_start;
4628 /* Now seek back in time */
4629 gst_qtdemux_move_stream (qtdemux, str, k_index);
4630 GST_DEBUG_OBJECT (qtdemux, "stream %d keyframe at %u, time position %"
4631 GST_TIME_FORMAT " playing from sample %u to %u", n, k_index,
4632 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4638 return GST_FLOW_EOS;
4642 * Gets the current qt segment start, stop and position for the
4643 * given time offset. This is used in update_segment()
4646 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
4647 QtDemuxStream * stream, GstClockTime offset,
4648 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
4650 GstClockTime seg_time;
4651 GstClockTime start, stop, time;
4652 QtDemuxSegment *segment;
4654 segment = &stream->segments[stream->segment_index];
4656 /* get time in this segment */
4657 seg_time = (offset - segment->time) * segment->rate;
4659 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4660 GST_TIME_ARGS (seg_time));
4662 if (G_UNLIKELY (seg_time > segment->duration)) {
4663 GST_LOG_OBJECT (stream->pad,
4664 "seg_time > segment->duration %" GST_TIME_FORMAT,
4665 GST_TIME_ARGS (segment->duration));
4666 seg_time = segment->duration;
4669 /* qtdemux->segment.stop is in outside-time-realm, whereas
4670 * segment->media_stop is in track-time-realm.
4672 * In order to compare the two, we need to bring segment.stop
4673 * into the track-time-realm
4675 * FIXME - does this comment still hold? Don't see any conversion here */
4677 stop = qtdemux->segment.stop;
4678 if (stop == GST_CLOCK_TIME_NONE)
4679 stop = qtdemux->segment.duration;
4680 if (stop == GST_CLOCK_TIME_NONE)
4681 stop = segment->media_stop;
4684 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4686 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4687 start = segment->time + seg_time;
4689 stop = start - seg_time + segment->duration;
4690 } else if (qtdemux->segment.rate >= 0) {
4691 start = MIN (segment->media_start + seg_time, stop);
4694 if (segment->media_start >= qtdemux->segment.start) {
4695 time = segment->time;
4697 time = segment->time + (qtdemux->segment.start - segment->media_start);
4700 start = MAX (segment->media_start, qtdemux->segment.start);
4701 stop = MIN (segment->media_start + seg_time, stop);
4710 * Updates the qt segment used for the stream and pushes a new segment event
4711 * downstream on this stream's pad.
4714 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4715 gint seg_idx, GstClockTime offset, GstClockTime * _start,
4716 GstClockTime * _stop)
4718 QtDemuxSegment *segment;
4719 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
4723 /* update the current segment */
4724 stream->segment_index = seg_idx;
4726 /* get the segment */
4727 segment = &stream->segments[seg_idx];
4729 if (G_UNLIKELY (offset < segment->time)) {
4730 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4731 GST_TIME_ARGS (segment->time));
4735 /* segment lies beyond total indicated duration */
4736 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4737 segment->time > qtdemux->segment.duration)) {
4738 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4739 " < segment->time %" GST_TIME_FORMAT,
4740 GST_TIME_ARGS (qtdemux->segment.duration),
4741 GST_TIME_ARGS (segment->time));
4745 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
4746 &start, &stop, &time);
4748 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
4749 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
4750 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
4752 /* combine global rate with that of the segment */
4753 rate = segment->rate * qtdemux->segment.rate;
4755 /* Copy flags from main segment */
4756 stream->segment.flags = qtdemux->segment.flags;
4758 /* update the segment values used for clipping */
4759 stream->segment.offset = qtdemux->segment.offset;
4760 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
4761 stream->segment.applied_rate = qtdemux->segment.applied_rate;
4762 stream->segment.rate = rate;
4763 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
4764 stream->cslg_shift);
4765 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
4766 stream->cslg_shift);
4767 stream->segment.time = time;
4768 stream->segment.position = stream->segment.start;
4770 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
4773 /* now prepare and send the segment */
4775 event = gst_event_new_segment (&stream->segment);
4776 if (qtdemux->segment_seqnum) {
4777 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
4779 gst_pad_push_event (stream->pad, event);
4780 /* assume we can send more data now */
4781 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
4782 /* clear to send tags on this pad now */
4783 gst_qtdemux_push_tags (qtdemux, stream);
4794 /* activate the given segment number @seg_idx of @stream at time @offset.
4795 * @offset is an absolute global position over all the segments.
4797 * This will push out a NEWSEGMENT event with the right values and
4798 * position the stream index to the first decodable sample before
4802 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4803 guint32 seg_idx, GstClockTime offset)
4805 QtDemuxSegment *segment;
4806 guint32 index, kf_index;
4807 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
4809 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
4810 seg_idx, GST_TIME_ARGS (offset));
4812 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
4816 segment = &stream->segments[stream->segment_index];
4818 /* in the fragmented case, we pick a fragment that starts before our
4819 * desired position and rely on downstream to wait for a keyframe
4820 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
4821 * tfra entries tells us which trun/sample the key unit is in, but we don't
4822 * make use of this additional information at the moment) */
4823 if (qtdemux->fragmented && !qtdemux->fragmented_seek_pending) {
4824 stream->to_sample = G_MAXUINT32;
4827 /* well, it will be taken care of below */
4828 qtdemux->fragmented_seek_pending = FALSE;
4829 /* FIXME ideally the do_fragmented_seek can be done right here,
4830 * rather than at loop level
4831 * (which might even allow handling edit lists in a fragmented file) */
4834 /* We don't need to look for a sample in push-based */
4835 if (!qtdemux->pullbased)
4838 /* and move to the keyframe before the indicated media time of the
4840 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
4841 if (qtdemux->segment.rate >= 0) {
4842 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
4843 stream->to_sample = G_MAXUINT32;
4844 GST_DEBUG_OBJECT (stream->pad,
4845 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4846 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
4847 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4849 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
4850 stream->to_sample = index;
4851 GST_DEBUG_OBJECT (stream->pad,
4852 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4853 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
4854 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4857 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
4858 "this is an empty segment");
4862 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
4863 * encountered an error and printed a message so we return appropriately */
4867 /* we're at the right spot */
4868 if (index == stream->sample_index) {
4869 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
4873 /* find keyframe of the target index */
4874 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
4877 /* indent does stupid stuff with stream->samples[].timestamp */
4879 /* if we move forwards, we don't have to go back to the previous
4880 * keyframe since we already sent that. We can also just jump to
4881 * the keyframe right before the target index if there is one. */
4882 if (index > stream->sample_index) {
4883 /* moving forwards check if we move past a keyframe */
4884 if (kf_index > stream->sample_index) {
4885 GST_DEBUG_OBJECT (stream->pad,
4886 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4887 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4888 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4889 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4891 GST_DEBUG_OBJECT (stream->pad,
4892 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
4893 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
4894 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
4897 GST_DEBUG_OBJECT (stream->pad,
4898 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4899 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4900 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4901 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4909 /* prepare to get the current sample of @stream, getting essential values.
4911 * This function will also prepare and send the segment when needed.
4913 * Return FALSE if the stream is EOS.
4918 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
4919 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
4920 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
4921 gboolean * keyframe)
4923 QtDemuxSample *sample;
4924 GstClockTime time_position;
4927 g_return_val_if_fail (stream != NULL, FALSE);
4929 time_position = stream->time_position;
4930 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
4933 seg_idx = stream->segment_index;
4934 if (G_UNLIKELY (seg_idx == -1)) {
4935 /* find segment corresponding to time_position if we are looking
4937 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
4940 /* different segment, activate it, sample_index will be set. */
4941 if (G_UNLIKELY (stream->segment_index != seg_idx))
4942 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
4944 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->segments[stream->
4946 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
4948 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
4949 " prepare empty sample");
4952 *pts = *dts = time_position;
4953 *duration = seg->duration - (time_position - seg->time);
4960 if (stream->sample_index == -1)
4961 stream->sample_index = 0;
4963 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
4964 stream->sample_index, stream->n_samples);
4966 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
4967 if (!qtdemux->fragmented)
4970 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
4974 GST_OBJECT_LOCK (qtdemux);
4975 flow = qtdemux_add_fragmented_samples (qtdemux);
4976 GST_OBJECT_UNLOCK (qtdemux);
4978 if (flow != GST_FLOW_OK)
4981 while (stream->sample_index >= stream->n_samples);
4984 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4985 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4986 stream->sample_index);
4990 /* now get the info for the sample we're at */
4991 sample = &stream->samples[stream->sample_index];
4993 *dts = QTSAMPLE_DTS (stream, sample);
4994 *pts = QTSAMPLE_PTS (stream, sample);
4995 *offset = sample->offset;
4996 *size = sample->size;
4997 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
4998 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5005 stream->time_position = GST_CLOCK_TIME_NONE;
5010 /* move to the next sample in @stream.
5012 * Moves to the next segment when needed.
5015 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
5017 QtDemuxSample *sample;
5018 QtDemuxSegment *segment;
5020 /* get current segment */
5021 segment = &stream->segments[stream->segment_index];
5023 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5024 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
5028 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
5029 /* Mark the stream as EOS */
5030 GST_DEBUG_OBJECT (qtdemux,
5031 "reached max allowed sample %u, mark EOS", stream->to_sample);
5032 stream->time_position = GST_CLOCK_TIME_NONE;
5036 /* move to next sample */
5037 stream->sample_index++;
5038 stream->offset_in_sample = 0;
5040 /* reached the last sample, we need the next segment */
5041 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
5044 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5045 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5046 stream->sample_index);
5050 /* get next sample */
5051 sample = &stream->samples[stream->sample_index];
5053 /* see if we are past the segment */
5054 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
5057 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
5058 /* inside the segment, update time_position, looks very familiar to
5059 * GStreamer segments, doesn't it? */
5060 stream->time_position =
5061 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
5063 /* not yet in segment, time does not yet increment. This means
5064 * that we are still prerolling keyframes to the decoder so it can
5065 * decode the first sample of the segment. */
5066 stream->time_position = segment->time;
5070 /* move to the next segment */
5073 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
5075 if (stream->segment_index == stream->n_segments - 1) {
5076 /* are we at the end of the last segment, we're EOS */
5077 stream->time_position = GST_CLOCK_TIME_NONE;
5079 /* else we're only at the end of the current segment */
5080 stream->time_position = segment->stop_time;
5082 /* make sure we select a new segment */
5084 /* accumulate previous segments */
5085 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
5086 stream->accumulated_base +=
5087 (stream->segment.stop -
5088 stream->segment.start) / ABS (stream->segment.rate);
5090 stream->segment_index = -1;
5095 gst_qtdemux_sync_streams (GstQTDemux * demux)
5099 if (demux->n_streams <= 1)
5102 for (i = 0; i < demux->n_streams; i++) {
5103 QtDemuxStream *stream;
5104 GstClockTime end_time;
5106 stream = demux->streams[i];
5111 /* TODO advance time on subtitle streams here, if any some day */
5113 /* some clips/trailers may have unbalanced streams at the end,
5114 * so send EOS on shorter stream to prevent stalling others */
5116 /* do not mess with EOS if SEGMENT seeking */
5117 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5120 if (demux->pullbased) {
5121 /* loop mode is sample time based */
5122 if (!STREAM_IS_EOS (stream))
5125 /* push mode is byte position based */
5126 if (stream->n_samples &&
5127 stream->samples[stream->n_samples - 1].offset >= demux->offset)
5131 if (stream->sent_eos)
5134 /* only act if some gap */
5135 end_time = stream->segments[stream->n_segments - 1].stop_time;
5136 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5137 ", stream end: %" GST_TIME_FORMAT,
5138 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5139 if (GST_CLOCK_TIME_IS_VALID (end_time)
5140 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5143 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5144 GST_PAD_NAME (stream->pad));
5145 stream->sent_eos = TRUE;
5146 event = gst_event_new_eos ();
5147 if (demux->segment_seqnum)
5148 gst_event_set_seqnum (event, demux->segment_seqnum);
5149 gst_pad_push_event (stream->pad, event);
5154 /* EOS and NOT_LINKED need to be combined. This means that we return:
5156 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
5157 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
5159 static GstFlowReturn
5160 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
5163 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
5166 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5169 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5171 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5175 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5176 * completely clipped
5178 * Should be used only with raw buffers */
5180 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5183 guint64 start, stop, cstart, cstop, diff;
5184 GstClockTime pts, duration;
5186 gint num_rate, denom_rate;
5191 osize = size = gst_buffer_get_size (buf);
5194 /* depending on the type, setup the clip parameters */
5195 if (stream->subtype == FOURCC_soun) {
5196 frame_size = CUR_STREAM (stream)->bytes_per_frame;
5197 num_rate = GST_SECOND;
5198 denom_rate = (gint) CUR_STREAM (stream)->rate;
5200 } else if (stream->subtype == FOURCC_vide) {
5202 num_rate = CUR_STREAM (stream)->fps_n;
5203 denom_rate = CUR_STREAM (stream)->fps_d;
5208 if (frame_size <= 0)
5209 goto bad_frame_size;
5211 /* we can only clip if we have a valid pts */
5212 pts = GST_BUFFER_PTS (buf);
5213 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5216 duration = GST_BUFFER_DURATION (buf);
5218 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5220 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5224 stop = start + duration;
5226 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5227 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5230 /* see if some clipping happened */
5231 diff = cstart - start;
5237 /* bring clipped time to samples and to bytes */
5238 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5241 GST_DEBUG_OBJECT (qtdemux,
5242 "clipping start to %" GST_TIME_FORMAT " %"
5243 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5249 diff = stop - cstop;
5254 /* bring clipped time to samples and then to bytes */
5255 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5257 GST_DEBUG_OBJECT (qtdemux,
5258 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5259 " bytes", GST_TIME_ARGS (cstop), diff);
5264 if (offset != 0 || size != osize)
5265 gst_buffer_resize (buf, offset, size);
5267 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5268 GST_BUFFER_PTS (buf) = pts;
5269 GST_BUFFER_DURATION (buf) = duration;
5273 /* dropped buffer */
5276 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5281 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5286 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5291 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5292 gst_buffer_unref (buf);
5298 gst_qtdemux_align_buffer (GstQTDemux * demux,
5299 GstBuffer * buffer, gsize alignment)
5303 gst_buffer_map (buffer, &map, GST_MAP_READ);
5305 if (map.size < sizeof (guintptr)) {
5306 gst_buffer_unmap (buffer, &map);
5310 if (((guintptr) map.data) & (alignment - 1)) {
5311 GstBuffer *new_buffer;
5312 GstAllocationParams params = { 0, alignment - 1, 0, 0, };
5314 new_buffer = gst_buffer_new_allocate (NULL,
5315 gst_buffer_get_size (buffer), ¶ms);
5317 /* Copy data "by hand", so ensure alignment is kept: */
5318 gst_buffer_fill (new_buffer, 0, map.data, map.size);
5320 gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
5321 GST_DEBUG_OBJECT (demux,
5322 "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
5325 gst_buffer_unmap (buffer, &map);
5326 gst_buffer_unref (buffer);
5331 gst_buffer_unmap (buffer, &map);
5335 /* the input buffer metadata must be writable,
5336 * but time/duration etc not yet set and need not be preserved */
5338 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5345 /* not many cases for now */
5346 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_mp4s)) {
5347 /* send a one time dvd clut event */
5348 if (stream->pending_event && stream->pad)
5349 gst_pad_push_event (stream->pad, stream->pending_event);
5350 stream->pending_event = NULL;
5353 if (G_UNLIKELY (stream->subtype != FOURCC_text
5354 && stream->subtype != FOURCC_sbtl &&
5355 stream->subtype != FOURCC_subp)) {
5359 gst_buffer_map (buf, &map, GST_MAP_READ);
5361 /* empty buffer is sent to terminate previous subtitle */
5362 if (map.size <= 2) {
5363 gst_buffer_unmap (buf, &map);
5364 gst_buffer_unref (buf);
5367 if (stream->subtype == FOURCC_subp) {
5368 /* That's all the processing needed for subpictures */
5369 gst_buffer_unmap (buf, &map);
5373 nsize = GST_READ_UINT16_BE (map.data);
5374 nsize = MIN (nsize, map.size - 2);
5376 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5379 /* takes care of UTF-8 validation or UTF-16 recognition,
5380 * no other encoding expected */
5381 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5382 gst_buffer_unmap (buf, &map);
5384 gst_buffer_unref (buf);
5385 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5387 /* this should not really happen unless the subtitle is corrupted */
5388 gst_buffer_unref (buf);
5392 /* FIXME ? convert optional subsequent style info to markup */
5397 /* Sets a buffer's attributes properly and pushes it downstream.
5398 * Also checks for additional actions and custom processing that may
5399 * need to be done first.
5401 static GstFlowReturn
5402 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
5403 QtDemuxStream * stream, GstBuffer * buf,
5404 GstClockTime dts, GstClockTime pts, GstClockTime duration,
5405 gboolean keyframe, GstClockTime position, guint64 byte_position)
5407 GstFlowReturn ret = GST_FLOW_OK;
5409 /* offset the timestamps according to the edit list */
5411 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) {
5415 gst_buffer_map (buf, &map, GST_MAP_READ);
5416 url = g_strndup ((gchar *) map.data, map.size);
5417 gst_buffer_unmap (buf, &map);
5418 if (url != NULL && strlen (url) != 0) {
5419 /* we have RTSP redirect now */
5420 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5421 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
5422 gst_structure_new ("redirect",
5423 "new-location", G_TYPE_STRING, url, NULL)));
5424 qtdemux->posted_redirect = TRUE;
5426 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
5432 /* position reporting */
5433 if (qtdemux->segment.rate >= 0) {
5434 qtdemux->segment.position = position;
5435 gst_qtdemux_sync_streams (qtdemux);
5438 if (G_UNLIKELY (!stream->pad)) {
5439 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
5440 gst_buffer_unref (buf);
5444 /* send out pending buffers */
5445 while (stream->buffers) {
5446 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
5448 if (G_UNLIKELY (stream->discont)) {
5449 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5450 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
5451 stream->discont = FALSE;
5453 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5456 if (stream->alignment > 1)
5457 buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
5458 gst_pad_push (stream->pad, buffer);
5460 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
5463 /* we're going to modify the metadata */
5464 buf = gst_buffer_make_writable (buf);
5466 if (G_UNLIKELY (stream->need_process))
5467 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
5473 GST_BUFFER_DTS (buf) = dts;
5474 GST_BUFFER_PTS (buf) = pts;
5475 GST_BUFFER_DURATION (buf) = duration;
5476 GST_BUFFER_OFFSET (buf) = -1;
5477 GST_BUFFER_OFFSET_END (buf) = -1;
5479 if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette))
5480 gst_buffer_append_memory (buf,
5481 gst_memory_ref (CUR_STREAM (stream)->rgb8_palette));
5483 if (G_UNLIKELY (CUR_STREAM (stream)->padding)) {
5484 gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1);
5487 if (G_UNLIKELY (qtdemux->element_index)) {
5488 GstClockTime stream_time;
5491 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
5493 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
5494 GST_LOG_OBJECT (qtdemux,
5495 "adding association %" GST_TIME_FORMAT "-> %"
5496 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
5497 gst_index_add_association (qtdemux->element_index,
5499 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
5500 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
5501 GST_FORMAT_BYTES, byte_position, NULL);
5506 if (stream->need_clip)
5507 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5509 if (G_UNLIKELY (buf == NULL))
5512 if (G_UNLIKELY (stream->discont)) {
5513 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5514 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5515 stream->discont = FALSE;
5517 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5521 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
5522 stream->on_keyframe = FALSE;
5524 stream->on_keyframe = TRUE;
5528 GST_LOG_OBJECT (qtdemux,
5529 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5530 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
5531 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
5532 GST_PAD_NAME (stream->pad));
5534 if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) {
5535 GstStructure *crypto_info;
5536 QtDemuxCencSampleSetInfo *info =
5537 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5541 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5542 gst_pad_push_event (stream->pad, event);
5545 if (info->crypto_info == NULL) {
5546 GST_DEBUG_OBJECT (qtdemux, "cenc metadata hasn't been parsed yet");
5547 gst_buffer_unref (buf);
5551 /* The end of the crypto_info array matches our n_samples position,
5552 * so count backward from there */
5553 index = stream->sample_index - stream->n_samples + info->crypto_info->len;
5554 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5555 /* steal structure from array */
5556 crypto_info = g_ptr_array_index (info->crypto_info, index);
5557 g_ptr_array_index (info->crypto_info, index) = NULL;
5558 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
5559 info->crypto_info->len);
5560 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5561 GST_ERROR_OBJECT (qtdemux, "failed to attach cenc metadata to buffer");
5563 GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
5564 index, stream->sample_index);
5568 if (stream->alignment > 1)
5569 buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
5571 ret = gst_pad_push (stream->pad, buf);
5573 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
5574 /* mark position in stream, we'll need this to know when to send GAP event */
5575 stream->segment.position = pts + duration;
5582 static const QtDemuxRandomAccessEntry *
5583 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5584 GstClockTime pos, gboolean after)
5586 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
5587 guint n_entries = stream->n_ra_entries;
5590 /* we assume the table is sorted */
5591 for (i = 0; i < n_entries; ++i) {
5592 if (entries[i].ts > pos)
5596 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
5597 * probably okay to assume that the index lists the very first fragment */
5604 return &entries[i - 1];
5608 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
5610 const QtDemuxRandomAccessEntry *best_entry = NULL;
5613 GST_OBJECT_LOCK (qtdemux);
5615 g_assert (qtdemux->n_streams > 0);
5617 /* first see if we can determine where to go to using mfra,
5618 * before we start clearing things */
5619 for (i = 0; i < qtdemux->n_streams; i++) {
5620 const QtDemuxRandomAccessEntry *entry;
5621 QtDemuxStream *stream;
5622 gboolean is_audio_or_video;
5624 stream = qtdemux->streams[i];
5626 if (stream->ra_entries == NULL)
5629 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
5630 is_audio_or_video = TRUE;
5632 is_audio_or_video = FALSE;
5635 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
5636 stream->time_position, !is_audio_or_video);
5638 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
5639 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
5641 stream->pending_seek = entry;
5643 /* decide position to jump to just based on audio/video tracks, not subs */
5644 if (!is_audio_or_video)
5647 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
5651 /* no luck, will handle seek otherwise */
5652 if (best_entry == NULL) {
5653 GST_OBJECT_UNLOCK (qtdemux);
5657 /* ok, now we can prepare for processing as of located moof */
5658 for (i = 0; i < qtdemux->n_streams; i++) {
5659 QtDemuxStream *stream;
5661 stream = qtdemux->streams[i];
5663 g_free (stream->samples);
5664 stream->samples = NULL;
5665 stream->n_samples = 0;
5666 stream->stbl_index = -1; /* no samples have yet been parsed */
5667 stream->sample_index = -1;
5669 if (stream->protection_scheme_info) {
5670 /* Clear out any old cenc crypto info entries as we'll move to a new moof */
5671 if (stream->protection_scheme_type == FOURCC_cenc) {
5672 QtDemuxCencSampleSetInfo *info =
5673 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5674 if (info->crypto_info) {
5675 g_ptr_array_free (info->crypto_info, TRUE);
5676 info->crypto_info = NULL;
5682 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
5683 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
5684 GST_TIME_ARGS (qtdemux->streams[0]->time_position),
5685 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
5687 qtdemux->moof_offset = best_entry->moof_offset;
5689 qtdemux_add_fragmented_samples (qtdemux);
5691 GST_OBJECT_UNLOCK (qtdemux);
5695 static GstFlowReturn
5696 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
5698 GstFlowReturn ret = GST_FLOW_OK;
5699 GstBuffer *buf = NULL;
5700 QtDemuxStream *stream;
5701 GstClockTime min_time;
5703 GstClockTime dts = GST_CLOCK_TIME_NONE;
5704 GstClockTime pts = GST_CLOCK_TIME_NONE;
5705 GstClockTime duration = 0;
5706 gboolean keyframe = FALSE;
5707 guint sample_size = 0;
5713 gst_qtdemux_push_pending_newsegment (qtdemux);
5715 if (qtdemux->fragmented_seek_pending) {
5716 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
5717 if (gst_qtdemux_do_fragmented_seek (qtdemux)) {
5718 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
5719 qtdemux->fragmented_seek_pending = FALSE;
5721 GST_INFO_OBJECT (qtdemux, "fragmented seek still pending");
5725 /* Figure out the next stream sample to output, min_time is expressed in
5726 * global time and runs over the edit list segments. */
5727 min_time = G_MAXUINT64;
5729 for (i = 0; i < qtdemux->n_streams; i++) {
5730 GstClockTime position;
5732 stream = qtdemux->streams[i];
5733 position = stream->time_position;
5735 /* position of -1 is EOS */
5736 if (position != GST_CLOCK_TIME_NONE && position < min_time) {
5737 min_time = position;
5742 if (G_UNLIKELY (index == -1)) {
5743 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
5747 /* check for segment end */
5748 if (G_UNLIKELY (qtdemux->segment.stop != -1
5749 && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
5750 || (qtdemux->segment.rate < 0
5751 && qtdemux->segment.start > min_time))
5752 && qtdemux->streams[index]->on_keyframe)) {
5753 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
5754 qtdemux->streams[index]->time_position = GST_CLOCK_TIME_NONE;
5758 /* gap events for subtitle streams */
5759 for (i = 0; i < qtdemux->n_streams; i++) {
5760 stream = qtdemux->streams[i];
5761 if (stream->pad && (stream->subtype == FOURCC_subp
5762 || stream->subtype == FOURCC_text
5763 || stream->subtype == FOURCC_sbtl)) {
5764 /* send one second gap events until the stream catches up */
5765 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
5766 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
5767 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
5768 stream->segment.position + GST_SECOND < min_time) {
5770 gst_event_new_gap (stream->segment.position, GST_SECOND);
5771 gst_pad_push_event (stream->pad, gap);
5772 stream->segment.position += GST_SECOND;
5777 stream = qtdemux->streams[index];
5778 /* fetch info for the current sample of this stream */
5779 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
5780 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
5783 gst_qtdemux_stream_check_and_change_stsd_index (qtdemux, stream);
5784 if (stream->new_caps) {
5785 gst_qtdemux_configure_stream (qtdemux, stream);
5786 qtdemux_do_allocation (qtdemux, stream);
5789 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
5790 if (G_UNLIKELY (qtdemux->
5791 segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
5792 if (stream->subtype == FOURCC_vide && !keyframe) {
5793 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on stream %d", index);
5798 GST_DEBUG_OBJECT (qtdemux,
5799 "pushing from stream %d, empty %d offset %" G_GUINT64_FORMAT
5800 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
5801 ", duration %" GST_TIME_FORMAT, index, empty, offset, sample_size,
5802 GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
5804 if (G_UNLIKELY (empty)) {
5805 /* empty segment, push a gap and move to the next one */
5806 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
5807 stream->segment.position = pts + duration;
5811 /* hmm, empty sample, skip and move to next sample */
5812 if (G_UNLIKELY (sample_size <= 0))
5815 /* last pushed sample was out of boundary, goto next sample */
5816 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
5819 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
5822 GST_DEBUG_OBJECT (qtdemux,
5823 "size %d larger than stream max_buffer_size %d, trimming",
5824 sample_size, stream->max_buffer_size);
5826 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
5829 if (qtdemux->cenc_aux_info_offset > 0) {
5832 GstBuffer *aux_info = NULL;
5834 /* pull the data stored before the sample */
5836 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
5837 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
5838 if (G_UNLIKELY (ret != GST_FLOW_OK))
5840 gst_buffer_map (aux_info, &map, GST_MAP_READ);
5841 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
5842 gst_byte_reader_init (&br, map.data + 8, map.size);
5843 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
5844 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
5845 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
5846 gst_buffer_unmap (aux_info, &map);
5847 gst_buffer_unref (aux_info);
5848 ret = GST_FLOW_ERROR;
5851 gst_buffer_unmap (aux_info, &map);
5852 gst_buffer_unref (aux_info);
5855 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
5858 if (stream->use_allocator) {
5859 /* if we have a per-stream allocator, use it */
5860 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
5863 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
5865 if (G_UNLIKELY (ret != GST_FLOW_OK))
5868 if (size != sample_size) {
5869 pts += gst_util_uint64_scale_int (GST_SECOND,
5870 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
5873 gst_util_uint64_scale_int (GST_SECOND,
5874 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
5877 gst_util_uint64_scale_int (GST_SECOND,
5878 size / CUR_STREAM (stream)->bytes_per_frame, stream->timescale);
5881 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
5882 dts, pts, duration, keyframe, min_time, offset);
5884 if (size != sample_size) {
5885 QtDemuxSample *sample = &stream->samples[stream->sample_index];
5886 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
5888 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
5890 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame);
5891 if (time_position >= segment->media_start) {
5892 /* inside the segment, update time_position, looks very familiar to
5893 * GStreamer segments, doesn't it? */
5894 stream->time_position = (time_position - segment->media_start) +
5897 /* not yet in segment, time does not yet increment. This means
5898 * that we are still prerolling keyframes to the decoder so it can
5899 * decode the first sample of the segment. */
5900 stream->time_position = segment->time;
5905 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
5906 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
5907 * we have no more data for the pad to push */
5908 if (ret == GST_FLOW_EOS)
5911 stream->offset_in_sample += size;
5912 if (stream->offset_in_sample >= sample_size) {
5913 gst_qtdemux_advance_sample (qtdemux, stream);
5918 gst_qtdemux_advance_sample (qtdemux, stream);
5926 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
5932 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
5933 /* EOS will be raised if all are EOS */
5940 gst_qtdemux_loop (GstPad * pad)
5942 GstQTDemux *qtdemux;
5946 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
5948 cur_offset = qtdemux->offset;
5949 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
5950 cur_offset, qt_demux_state_string (qtdemux->state));
5952 switch (qtdemux->state) {
5953 case QTDEMUX_STATE_INITIAL:
5954 case QTDEMUX_STATE_HEADER:
5955 ret = gst_qtdemux_loop_state_header (qtdemux);
5957 case QTDEMUX_STATE_MOVIE:
5958 ret = gst_qtdemux_loop_state_movie (qtdemux);
5959 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
5960 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
5968 /* if something went wrong, pause */
5969 if (ret != GST_FLOW_OK)
5973 gst_object_unref (qtdemux);
5979 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
5980 (NULL), ("streaming stopped, invalid state"));
5981 gst_pad_pause_task (pad);
5982 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5987 const gchar *reason = gst_flow_get_name (ret);
5989 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
5991 gst_pad_pause_task (pad);
5993 /* fatal errors need special actions */
5995 if (ret == GST_FLOW_EOS) {
5996 if (qtdemux->n_streams == 0) {
5997 /* we have no streams, post an error */
5998 gst_qtdemux_post_no_playable_stream_error (qtdemux);
6000 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
6003 if ((stop = qtdemux->segment.stop) == -1)
6004 stop = qtdemux->segment.duration;
6006 if (qtdemux->segment.rate >= 0) {
6007 GstMessage *message;
6010 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
6011 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6012 GST_FORMAT_TIME, stop);
6013 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
6014 if (qtdemux->segment_seqnum) {
6015 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6016 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6018 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6019 gst_qtdemux_push_event (qtdemux, event);
6021 GstMessage *message;
6024 /* For Reverse Playback */
6025 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
6026 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6027 GST_FORMAT_TIME, qtdemux->segment.start);
6028 event = gst_event_new_segment_done (GST_FORMAT_TIME,
6029 qtdemux->segment.start);
6030 if (qtdemux->segment_seqnum) {
6031 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6032 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6034 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6035 gst_qtdemux_push_event (qtdemux, event);
6040 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
6041 event = gst_event_new_eos ();
6042 if (qtdemux->segment_seqnum)
6043 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6044 gst_qtdemux_push_event (qtdemux, event);
6046 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
6047 GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
6048 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6057 * Returns if there are samples to be played.
6060 has_next_entry (GstQTDemux * demux)
6062 QtDemuxStream *stream;
6065 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
6067 for (i = 0; i < demux->n_streams; i++) {
6068 stream = demux->streams[i];
6070 if (stream->sample_index == -1) {
6071 stream->sample_index = 0;
6072 stream->offset_in_sample = 0;
6075 if (stream->sample_index >= stream->n_samples) {
6076 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
6079 GST_DEBUG_OBJECT (demux, "Found a sample");
6083 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
6090 * Returns the size of the first entry at the current offset.
6091 * If -1, there are none (which means EOS or empty file).
6094 next_entry_size (GstQTDemux * demux)
6096 QtDemuxStream *stream;
6099 guint64 smalloffs = (guint64) - 1;
6100 QtDemuxSample *sample;
6102 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
6105 for (i = 0; i < demux->n_streams; i++) {
6106 stream = demux->streams[i];
6108 if (stream->sample_index == -1) {
6109 stream->sample_index = 0;
6110 stream->offset_in_sample = 0;
6113 if (stream->sample_index >= stream->n_samples) {
6114 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
6118 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
6119 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
6120 stream->sample_index);
6124 sample = &stream->samples[stream->sample_index];
6126 GST_LOG_OBJECT (demux,
6127 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
6128 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
6129 sample->offset, sample->size);
6131 if (((smalloffs == -1)
6132 || (sample->offset < smalloffs)) && (sample->size)) {
6134 smalloffs = sample->offset;
6138 GST_LOG_OBJECT (demux,
6139 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
6140 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
6145 stream = demux->streams[smallidx];
6146 sample = &stream->samples[stream->sample_index];
6148 if (sample->offset >= demux->offset) {
6149 demux->todrop = sample->offset - demux->offset;
6150 return sample->size + demux->todrop;
6153 GST_DEBUG_OBJECT (demux,
6154 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
6159 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
6161 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
6163 gst_element_post_message (GST_ELEMENT_CAST (demux),
6164 gst_message_new_element (GST_OBJECT_CAST (demux),
6165 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
6169 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
6174 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
6177 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
6178 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
6179 GST_SEEK_TYPE_NONE, -1);
6181 /* store seqnum to drop flush events, they don't need to reach downstream */
6182 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
6183 res = gst_pad_push_event (demux->sinkpad, event);
6184 demux->offset_seek_seqnum = 0;
6189 /* check for seekable upstream, above and beyond a mere query */
6191 gst_qtdemux_check_seekability (GstQTDemux * demux)
6194 gboolean seekable = FALSE;
6195 gint64 start = -1, stop = -1;
6197 if (demux->upstream_size)
6200 if (demux->upstream_format_is_time)
6203 query = gst_query_new_seeking (GST_FORMAT_BYTES);
6204 if (!gst_pad_peer_query (demux->sinkpad, query)) {
6205 GST_DEBUG_OBJECT (demux, "seeking query failed");
6209 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
6211 /* try harder to query upstream size if we didn't get it the first time */
6212 if (seekable && stop == -1) {
6213 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
6214 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
6217 /* if upstream doesn't know the size, it's likely that it's not seekable in
6218 * practice even if it technically may be seekable */
6219 if (seekable && (start != 0 || stop <= start)) {
6220 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
6225 gst_query_unref (query);
6227 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
6228 G_GUINT64_FORMAT ")", seekable, start, stop);
6229 demux->upstream_seekable = seekable;
6230 demux->upstream_size = seekable ? stop : -1;
6234 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
6236 g_return_if_fail (bytes <= demux->todrop);
6238 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
6239 gst_adapter_flush (demux->adapter, bytes);
6240 demux->neededbytes -= bytes;
6241 demux->offset += bytes;
6242 demux->todrop -= bytes;
6246 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
6248 if (G_UNLIKELY (demux->pending_newsegment)) {
6251 gst_qtdemux_push_pending_newsegment (demux);
6252 /* clear to send tags on all streams */
6253 for (i = 0; i < demux->n_streams; i++) {
6254 QtDemuxStream *stream;
6255 stream = demux->streams[i];
6256 gst_qtdemux_push_tags (demux, stream);
6257 if (CUR_STREAM (stream)->sparse) {
6258 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
6259 gst_pad_push_event (stream->pad,
6260 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
6267 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
6268 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
6270 GstClockTime ts, dur;
6275 stream->segments[segment_index].duration - (pos -
6276 stream->segments[segment_index].time);
6277 gap = gst_event_new_gap (ts, dur);
6278 stream->time_position += dur;
6280 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
6281 "segment: %" GST_PTR_FORMAT, gap);
6282 gst_pad_push_event (stream->pad, gap);
6286 gst_qtdemux_stream_send_initial_gap_segments (GstQTDemux * demux,
6287 QtDemuxStream * stream)
6291 /* Push any initial gap segments before proceeding to the
6293 for (i = 0; i < stream->n_segments; i++) {
6294 gst_qtdemux_activate_segment (demux, stream, i, stream->time_position);
6296 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
6297 gst_qtdemux_send_gap_for_segment (demux, stream, i,
6298 stream->time_position);
6300 /* Only support empty segment at the beginning followed by
6301 * one non-empty segment, this was checked when parsing the
6302 * edts atom, arriving here is unexpected */
6303 g_assert (i + 1 == stream->n_segments);
6309 static GstFlowReturn
6310 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
6314 demux = GST_QTDEMUX (parent);
6316 GST_DEBUG_OBJECT (demux,
6317 "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
6318 " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
6319 G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
6320 GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
6321 gst_buffer_get_size (inbuf), demux->offset);
6323 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
6324 gboolean is_gap_input = FALSE;
6327 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
6329 for (i = 0; i < demux->n_streams; i++) {
6330 demux->streams[i]->discont = TRUE;
6333 /* Check if we can land back on our feet in the case where upstream is
6334 * handling the seeking/pushing of samples with gaps in between (like
6335 * in the case of trick-mode DASH for example) */
6336 if (demux->upstream_format_is_time
6337 && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
6339 for (i = 0; i < demux->n_streams; i++) {
6341 GST_LOG_OBJECT (demux,
6342 "Stream #%d , checking if offset %" G_GUINT64_FORMAT
6343 " is a sample start", i, GST_BUFFER_OFFSET (inbuf));
6345 gst_qtdemux_find_index_for_given_media_offset_linear (demux,
6346 demux->streams[i], GST_BUFFER_OFFSET (inbuf));
6348 QtDemuxSample *sample = &demux->streams[i]->samples[res];
6349 GST_LOG_OBJECT (demux,
6350 "Checking if sample %d from stream %d is valid (offset:%"
6351 G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res, i,
6352 sample->offset, sample->size);
6353 if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
6354 GST_LOG_OBJECT (demux,
6355 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
6357 is_gap_input = TRUE;
6358 /* We can go back to standard playback mode */
6359 demux->state = QTDEMUX_STATE_MOVIE;
6360 /* Remember which sample this stream is at */
6361 demux->streams[i]->sample_index = res;
6362 /* Finally update all push-based values to the expected values */
6363 demux->neededbytes = demux->streams[i]->samples[res].size;
6364 demux->offset = GST_BUFFER_OFFSET (inbuf);
6366 demux->mdatsize - demux->offset + demux->mdatoffset;
6371 if (!is_gap_input) {
6372 GST_DEBUG_OBJECT (demux, "Resetting, actual DISCONT");
6373 /* Reset state if it's a real discont */
6374 demux->neededbytes = 16;
6375 demux->state = QTDEMUX_STATE_INITIAL;
6376 demux->offset = GST_BUFFER_OFFSET (inbuf);
6377 gst_adapter_clear (demux->adapter);
6380 /* Reverse fragmented playback, need to flush all we have before
6381 * consuming a new fragment.
6382 * The samples array have the timestamps calculated by accumulating the
6383 * durations but this won't work for reverse playback of fragments as
6384 * the timestamps of a subsequent fragment should be smaller than the
6385 * previously received one. */
6386 if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
6387 gst_qtdemux_process_adapter (demux, TRUE);
6388 for (i = 0; i < demux->n_streams; i++)
6389 gst_qtdemux_stream_flush_samples_data (demux, demux->streams[i]);
6393 gst_adapter_push (demux->adapter, inbuf);
6395 GST_DEBUG_OBJECT (demux,
6396 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
6397 demux->neededbytes, gst_adapter_available (demux->adapter));
6399 return gst_qtdemux_process_adapter (demux, FALSE);
6402 static GstFlowReturn
6403 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
6405 GstFlowReturn ret = GST_FLOW_OK;
6407 /* we never really mean to buffer that much */
6408 if (demux->neededbytes == -1) {
6412 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
6413 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
6415 #ifndef GST_DISABLE_GST_DEBUG
6417 guint64 discont_offset, distance_from_discont;
6419 discont_offset = gst_adapter_offset_at_discont (demux->adapter);
6420 distance_from_discont =
6421 gst_adapter_distance_from_discont (demux->adapter);
6423 GST_DEBUG_OBJECT (demux,
6424 "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
6425 " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
6426 " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
6427 demux->offset, discont_offset, distance_from_discont);
6431 switch (demux->state) {
6432 case QTDEMUX_STATE_INITIAL:{
6437 gst_qtdemux_check_seekability (demux);
6439 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6441 /* get fourcc/length, set neededbytes */
6442 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
6444 gst_adapter_unmap (demux->adapter);
6446 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
6447 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
6449 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6450 (_("This file is invalid and cannot be played.")),
6451 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
6452 GST_FOURCC_ARGS (fourcc)));
6453 ret = GST_FLOW_ERROR;
6456 if (fourcc == FOURCC_mdat) {
6457 gint next_entry = next_entry_size (demux);
6458 if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
6459 /* we have the headers, start playback */
6460 demux->state = QTDEMUX_STATE_MOVIE;
6461 demux->neededbytes = next_entry;
6462 demux->mdatleft = size;
6463 demux->mdatsize = demux->mdatleft;
6465 /* no headers yet, try to get them */
6468 guint64 old, target;
6471 old = demux->offset;
6472 target = old + size;
6474 /* try to jump over the atom with a seek */
6475 /* only bother if it seems worth doing so,
6476 * and avoids possible upstream/server problems */
6477 if (demux->upstream_seekable &&
6478 demux->upstream_size > 4 * (1 << 20)) {
6479 res = qtdemux_seek_offset (demux, target);
6481 GST_DEBUG_OBJECT (demux, "skipping seek");
6486 GST_DEBUG_OBJECT (demux, "seek success");
6487 /* remember the offset fo the first mdat so we can seek back to it
6488 * after we have the headers */
6489 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
6490 demux->first_mdat = old;
6491 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
6494 /* seek worked, continue reading */
6495 demux->offset = target;
6496 demux->neededbytes = 16;
6497 demux->state = QTDEMUX_STATE_INITIAL;
6499 /* seek failed, need to buffer */
6500 demux->offset = old;
6501 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
6502 /* there may be multiple mdat (or alike) buffers */
6504 if (demux->mdatbuffer)
6505 bs = gst_buffer_get_size (demux->mdatbuffer);
6508 if (size + bs > 10 * (1 << 20))
6510 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
6511 demux->neededbytes = size;
6512 if (!demux->mdatbuffer)
6513 demux->mdatoffset = demux->offset;
6516 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
6517 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6518 (_("This file is invalid and cannot be played.")),
6519 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
6520 GST_FOURCC_ARGS (fourcc), size));
6521 ret = GST_FLOW_ERROR;
6524 /* this means we already started buffering and still no moov header,
6525 * let's continue buffering everything till we get moov */
6526 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
6527 || fourcc == FOURCC_moof))
6529 demux->neededbytes = size;
6530 demux->state = QTDEMUX_STATE_HEADER;
6534 case QTDEMUX_STATE_HEADER:{
6538 GST_DEBUG_OBJECT (demux, "In header");
6540 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6542 /* parse the header */
6543 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
6545 if (fourcc == FOURCC_moov) {
6548 /* in usual fragmented setup we could try to scan for more
6549 * and end up at the the moov (after mdat) again */
6550 if (demux->got_moov && demux->n_streams > 0 &&
6552 || demux->last_moov_offset == demux->offset)) {
6553 GST_DEBUG_OBJECT (demux,
6554 "Skipping moov atom as we have (this) one already");
6556 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
6558 if (demux->got_moov && demux->fragmented) {
6559 GST_DEBUG_OBJECT (demux,
6560 "Got a second moov, clean up data from old one");
6561 if (demux->moov_node_compressed) {
6562 g_node_destroy (demux->moov_node_compressed);
6563 if (demux->moov_node)
6564 g_free (demux->moov_node->data);
6566 demux->moov_node_compressed = NULL;
6567 if (demux->moov_node)
6568 g_node_destroy (demux->moov_node);
6569 demux->moov_node = NULL;
6571 /* prepare newsegment to send when streaming actually starts */
6572 if (!demux->pending_newsegment) {
6573 demux->pending_newsegment =
6574 gst_event_new_segment (&demux->segment);
6575 if (demux->segment_seqnum)
6576 gst_event_set_seqnum (demux->pending_newsegment,
6577 demux->segment_seqnum);
6581 demux->last_moov_offset = demux->offset;
6583 qtdemux_parse_moov (demux, data, demux->neededbytes);
6584 qtdemux_node_dump (demux, demux->moov_node);
6585 qtdemux_parse_tree (demux);
6586 qtdemux_prepare_streams (demux);
6587 if (!demux->got_moov)
6588 qtdemux_expose_streams (demux);
6591 for (n = 0; n < demux->n_streams; n++) {
6592 QtDemuxStream *stream = demux->streams[n];
6594 gst_qtdemux_configure_stream (demux, stream);
6598 demux->got_moov = TRUE;
6599 gst_qtdemux_check_send_pending_segment (demux);
6601 /* fragmented streams headers shouldn't contain edts atoms */
6602 if (!demux->fragmented) {
6603 for (n = 0; n < demux->n_streams; n++) {
6604 gst_qtdemux_stream_send_initial_gap_segments (demux,
6609 if (demux->moov_node_compressed) {
6610 g_node_destroy (demux->moov_node_compressed);
6611 g_free (demux->moov_node->data);
6613 demux->moov_node_compressed = NULL;
6614 g_node_destroy (demux->moov_node);
6615 demux->moov_node = NULL;
6616 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
6618 } else if (fourcc == FOURCC_moof) {
6619 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
6621 GstClockTime prev_pts;
6622 guint64 prev_offset;
6623 guint64 adapter_discont_offset, adapter_discont_dist;
6625 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
6628 * The timestamp of the moof buffer is relevant as some scenarios
6629 * won't have the initial timestamp in the atoms. Whenever a new
6630 * buffer has started, we get that buffer's PTS and use it as a base
6631 * timestamp for the trun entries.
6633 * To keep track of the current buffer timestamp and starting point
6634 * we use gst_adapter_prev_pts that gives us the PTS and the distance
6635 * from the beggining of the buffer, with the distance and demux->offset
6636 * we know if it is still the same buffer or not.
6638 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
6639 prev_offset = demux->offset - dist;
6640 if (demux->fragment_start_offset == -1
6641 || prev_offset > demux->fragment_start_offset) {
6642 demux->fragment_start_offset = prev_offset;
6643 demux->fragment_start = prev_pts;
6644 GST_DEBUG_OBJECT (demux,
6645 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
6646 GST_TIME_FORMAT, demux->fragment_start_offset,
6647 GST_TIME_ARGS (demux->fragment_start));
6650 /* We can't use prev_offset() here because this would require
6651 * upstream to set consistent and correct offsets on all buffers
6652 * since the discont. Nothing ever did that in the past and we
6653 * would break backwards compatibility here then.
6654 * Instead take the offset we had at the last discont and count
6655 * the bytes from there. This works with old code as there would
6656 * be no discont between moov and moof, and also works with
6657 * adaptivedemux which correctly sets offset and will set the
6658 * DISCONT flag accordingly when needed.
6660 * We also only do this for upstream TIME segments as otherwise
6661 * there are potential backwards compatibility problems with
6662 * seeking in PUSH mode and upstream providing inconsistent
6664 adapter_discont_offset =
6665 gst_adapter_offset_at_discont (demux->adapter);
6666 adapter_discont_dist =
6667 gst_adapter_distance_from_discont (demux->adapter);
6669 GST_DEBUG_OBJECT (demux,
6670 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
6671 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
6672 demux->offset, adapter_discont_offset, adapter_discont_dist);
6674 if (demux->upstream_format_is_time) {
6675 demux->moof_offset = adapter_discont_offset;
6676 if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
6677 demux->moof_offset += adapter_discont_dist;
6678 if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
6679 demux->moof_offset = demux->offset;
6681 demux->moof_offset = demux->offset;
6684 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
6685 demux->moof_offset, NULL)) {
6686 gst_adapter_unmap (demux->adapter);
6687 ret = GST_FLOW_ERROR;
6690 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
6691 if (demux->mss_mode && !demux->exposed) {
6692 if (!demux->pending_newsegment) {
6693 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
6694 demux->pending_newsegment =
6695 gst_event_new_segment (&demux->segment);
6696 if (demux->segment_seqnum)
6697 gst_event_set_seqnum (demux->pending_newsegment,
6698 demux->segment_seqnum);
6700 qtdemux_expose_streams (demux);
6703 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
6705 } else if (fourcc == FOURCC_ftyp) {
6706 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
6707 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
6708 } else if (fourcc == FOURCC_uuid) {
6709 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
6710 qtdemux_parse_uuid (demux, data, demux->neededbytes);
6711 } else if (fourcc == FOURCC_sidx) {
6712 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
6713 qtdemux_parse_sidx (demux, data, demux->neededbytes);
6717 /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
6721 /* [free] and [skip] are padding atoms */
6722 GST_DEBUG_OBJECT (demux,
6723 "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
6724 GST_FOURCC_ARGS (fourcc));
6727 GST_WARNING_OBJECT (demux,
6728 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
6729 GST_FOURCC_ARGS (fourcc));
6730 /* Let's jump that one and go back to initial state */
6734 gst_adapter_unmap (demux->adapter);
6737 if (demux->mdatbuffer && demux->n_streams) {
6738 gsize remaining_data_size = 0;
6740 /* the mdat was before the header */
6741 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
6742 demux->n_streams, demux->mdatbuffer);
6743 /* restore our adapter/offset view of things with upstream;
6744 * put preceding buffered data ahead of current moov data.
6745 * This should also handle evil mdat, moov, mdat cases and alike */
6746 gst_adapter_flush (demux->adapter, demux->neededbytes);
6748 /* Store any remaining data after the mdat for later usage */
6749 remaining_data_size = gst_adapter_available (demux->adapter);
6750 if (remaining_data_size > 0) {
6751 g_assert (demux->restoredata_buffer == NULL);
6752 demux->restoredata_buffer =
6753 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
6754 demux->restoredata_offset = demux->offset + demux->neededbytes;
6755 GST_DEBUG_OBJECT (demux,
6756 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
6757 G_GUINT64_FORMAT, remaining_data_size,
6758 demux->restoredata_offset);
6761 gst_adapter_push (demux->adapter, demux->mdatbuffer);
6762 demux->mdatbuffer = NULL;
6763 demux->offset = demux->mdatoffset;
6764 demux->neededbytes = next_entry_size (demux);
6765 demux->state = QTDEMUX_STATE_MOVIE;
6766 demux->mdatleft = gst_adapter_available (demux->adapter);
6767 demux->mdatsize = demux->mdatleft;
6769 GST_DEBUG_OBJECT (demux, "Carrying on normally");
6770 gst_adapter_flush (demux->adapter, demux->neededbytes);
6772 /* only go back to the mdat if there are samples to play */
6773 if (demux->got_moov && demux->first_mdat != -1
6774 && has_next_entry (demux)) {
6777 /* we need to seek back */
6778 res = qtdemux_seek_offset (demux, demux->first_mdat);
6780 demux->offset = demux->first_mdat;
6782 GST_DEBUG_OBJECT (demux, "Seek back failed");
6785 demux->offset += demux->neededbytes;
6787 demux->neededbytes = 16;
6788 demux->state = QTDEMUX_STATE_INITIAL;
6793 case QTDEMUX_STATE_BUFFER_MDAT:{
6797 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
6799 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6800 gst_buffer_extract (buf, 0, fourcc, 4);
6801 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
6802 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
6803 if (demux->mdatbuffer)
6804 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
6806 demux->mdatbuffer = buf;
6807 demux->offset += demux->neededbytes;
6808 demux->neededbytes = 16;
6809 demux->state = QTDEMUX_STATE_INITIAL;
6810 gst_qtdemux_post_progress (demux, 1, 1);
6814 case QTDEMUX_STATE_MOVIE:{
6815 QtDemuxStream *stream = NULL;
6816 QtDemuxSample *sample;
6818 GstClockTime dts, pts, duration;
6821 GST_DEBUG_OBJECT (demux,
6822 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
6824 if (demux->fragmented) {
6825 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
6827 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
6828 /* if needed data starts within this atom,
6829 * then it should not exceed this atom */
6830 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
6831 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6832 (_("This file is invalid and cannot be played.")),
6833 ("sample data crosses atom boundary"));
6834 ret = GST_FLOW_ERROR;
6837 demux->mdatleft -= demux->neededbytes;
6839 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
6840 /* so we are dropping more than left in this atom */
6841 gst_qtdemux_drop_data (demux, demux->mdatleft);
6842 demux->mdatleft = 0;
6844 /* need to resume atom parsing so we do not miss any other pieces */
6845 demux->state = QTDEMUX_STATE_INITIAL;
6846 demux->neededbytes = 16;
6848 /* check if there was any stored post mdat data from previous buffers */
6849 if (demux->restoredata_buffer) {
6850 g_assert (gst_adapter_available (demux->adapter) == 0);
6852 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
6853 demux->restoredata_buffer = NULL;
6854 demux->offset = demux->restoredata_offset;
6861 if (demux->todrop) {
6862 if (demux->cenc_aux_info_offset > 0) {
6866 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
6867 data = gst_adapter_map (demux->adapter, demux->todrop);
6868 gst_byte_reader_init (&br, data + 8, demux->todrop);
6869 if (!qtdemux_parse_cenc_aux_info (demux, demux->streams[0], &br,
6870 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
6871 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
6872 ret = GST_FLOW_ERROR;
6873 gst_adapter_unmap (demux->adapter);
6874 g_free (demux->cenc_aux_info_sizes);
6875 demux->cenc_aux_info_sizes = NULL;
6878 demux->cenc_aux_info_offset = 0;
6879 g_free (demux->cenc_aux_info_sizes);
6880 demux->cenc_aux_info_sizes = NULL;
6881 gst_adapter_unmap (demux->adapter);
6883 gst_qtdemux_drop_data (demux, demux->todrop);
6887 /* initial newsegment sent here after having added pads,
6888 * possible others in sink_event */
6889 gst_qtdemux_check_send_pending_segment (demux);
6891 /* Figure out which stream this packet belongs to */
6892 for (i = 0; i < demux->n_streams; i++) {
6893 stream = demux->streams[i];
6894 if (stream->sample_index >= stream->n_samples)
6896 GST_LOG_OBJECT (demux,
6897 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
6898 " / size:%d)", i, stream->sample_index,
6899 stream->samples[stream->sample_index].offset,
6900 stream->samples[stream->sample_index].size);
6902 if (stream->samples[stream->sample_index].offset == demux->offset)
6906 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
6907 goto unknown_stream;
6909 gst_qtdemux_stream_check_and_change_stsd_index (demux, stream);
6911 if (stream->new_caps) {
6912 gst_qtdemux_configure_stream (demux, stream);
6915 /* Put data in a buffer, set timestamps, caps, ... */
6916 sample = &stream->samples[stream->sample_index];
6918 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
6919 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
6920 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
6922 dts = QTSAMPLE_DTS (stream, sample);
6923 pts = QTSAMPLE_PTS (stream, sample);
6924 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
6925 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
6927 /* check for segment end */
6928 if (G_UNLIKELY (demux->segment.stop != -1
6929 && demux->segment.stop <= pts && stream->on_keyframe)) {
6930 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
6931 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
6933 /* skip this data, stream is EOS */
6934 gst_adapter_flush (demux->adapter, demux->neededbytes);
6935 demux->offset += demux->neededbytes;
6937 /* check if all streams are eos */
6939 for (i = 0; i < demux->n_streams; i++) {
6940 if (!STREAM_IS_EOS (demux->streams[i])) {
6949 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6951 /* FIXME: should either be an assert or a plain check */
6952 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
6954 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
6955 dts, pts, duration, keyframe, dts, demux->offset);
6959 ret = gst_qtdemux_combine_flows (demux, stream, ret);
6961 /* skip this data, stream is EOS */
6962 gst_adapter_flush (demux->adapter, demux->neededbytes);
6965 stream->sample_index++;
6966 stream->offset_in_sample = 0;
6968 /* update current offset and figure out size of next buffer */
6969 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
6970 demux->offset, demux->neededbytes);
6971 demux->offset += demux->neededbytes;
6972 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
6976 if (ret == GST_FLOW_EOS) {
6977 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
6978 demux->neededbytes = -1;
6982 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
6983 if (demux->fragmented) {
6984 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
6985 /* there may be more to follow, only finish this atom */
6986 demux->todrop = demux->mdatleft;
6987 demux->neededbytes = demux->todrop;
6992 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
6993 goto non_ok_unlinked_flow;
7002 /* when buffering movie data, at least show user something is happening */
7003 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
7004 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
7005 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
7006 demux->neededbytes);
7013 non_ok_unlinked_flow:
7015 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
7016 gst_flow_get_name (ret));
7021 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
7022 ret = GST_FLOW_ERROR;
7027 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
7033 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7034 (NULL), ("qtdemuxer invalid state %d", demux->state));
7035 ret = GST_FLOW_ERROR;
7040 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7041 (NULL), ("no 'moov' atom within the first 10 MB"));
7042 ret = GST_FLOW_ERROR;
7048 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
7053 query = gst_query_new_scheduling ();
7055 if (!gst_pad_peer_query (sinkpad, query)) {
7056 gst_query_unref (query);
7060 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
7061 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
7062 gst_query_unref (query);
7067 GST_DEBUG_OBJECT (sinkpad, "activating pull");
7068 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
7072 GST_DEBUG_OBJECT (sinkpad, "activating push");
7073 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
7078 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
7079 GstPadMode mode, gboolean active)
7082 GstQTDemux *demux = GST_QTDEMUX (parent);
7085 case GST_PAD_MODE_PUSH:
7086 demux->pullbased = FALSE;
7089 case GST_PAD_MODE_PULL:
7091 demux->pullbased = TRUE;
7092 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
7095 res = gst_pad_stop_task (sinkpad);
7107 qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
7113 memset (&z, 0, sizeof (z));
7118 if ((ret = inflateInit (&z)) != Z_OK) {
7119 GST_ERROR ("inflateInit() returned %d", ret);
7123 z.next_in = z_buffer;
7124 z.avail_in = z_length;
7126 buffer = (guint8 *) g_malloc (*length);
7127 z.avail_out = *length;
7128 z.next_out = (Bytef *) buffer;
7130 ret = inflate (&z, Z_NO_FLUSH);
7131 if (ret == Z_STREAM_END) {
7133 } else if (ret != Z_OK) {
7134 GST_WARNING ("inflate() returned %d", ret);
7139 buffer = (guint8 *) g_realloc (buffer, *length);
7140 z.next_out = (Bytef *) (buffer + z.total_out);
7141 z.avail_out += 4096;
7142 } while (z.avail_in > 0);
7144 if (ret != Z_STREAM_END) {
7149 *length = z.total_out;
7156 #endif /* HAVE_ZLIB */
7159 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
7163 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
7165 /* counts as header data */
7166 qtdemux->header_size += length;
7168 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
7169 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
7171 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
7178 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
7179 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
7180 if (dcom == NULL || cmvd == NULL)
7181 goto invalid_compression;
7183 dcom_len = QT_UINT32 (dcom->data);
7185 goto invalid_compression;
7187 method = QT_FOURCC ((guint8 *) dcom->data + 8);
7191 guint uncompressed_length;
7192 guint compressed_length;
7196 cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
7198 goto invalid_compression;
7200 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
7201 compressed_length = cmvd_len - 12;
7202 GST_LOG ("length = %u", uncompressed_length);
7205 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
7206 compressed_length, &uncompressed_length);
7209 qtdemux->moov_node_compressed = qtdemux->moov_node;
7210 qtdemux->moov_node = g_node_new (buf);
7212 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
7213 uncompressed_length);
7217 #endif /* HAVE_ZLIB */
7219 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
7220 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
7227 invalid_compression:
7229 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
7235 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
7238 while (G_UNLIKELY (buf < end)) {
7242 if (G_UNLIKELY (buf + 4 > end)) {
7243 GST_LOG_OBJECT (qtdemux, "buffer overrun");
7246 len = QT_UINT32 (buf);
7247 if (G_UNLIKELY (len == 0)) {
7248 GST_LOG_OBJECT (qtdemux, "empty container");
7251 if (G_UNLIKELY (len < 8)) {
7252 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
7255 if (G_UNLIKELY (len > (end - buf))) {
7256 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
7257 (gint) (end - buf));
7261 child = g_node_new ((guint8 *) buf);
7262 g_node_append (node, child);
7263 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
7264 qtdemux_parse_node (qtdemux, child, buf, len);
7272 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
7275 int len = QT_UINT32 (xdxt->data);
7276 guint8 *buf = xdxt->data;
7277 guint8 *end = buf + len;
7280 /* skip size and type */
7288 size = QT_UINT32 (buf);
7289 type = QT_FOURCC (buf + 4);
7291 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
7293 if (buf + size > end || size <= 0)
7299 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
7300 GST_FOURCC_ARGS (type));
7304 buffer = gst_buffer_new_and_alloc (size);
7305 gst_buffer_fill (buffer, 0, buf, size);
7306 stream->buffers = g_slist_append (stream->buffers, buffer);
7307 GST_LOG_OBJECT (qtdemux, "parsing theora header");
7310 buffer = gst_buffer_new_and_alloc (size);
7311 gst_buffer_fill (buffer, 0, buf, size);
7312 stream->buffers = g_slist_append (stream->buffers, buffer);
7313 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
7316 buffer = gst_buffer_new_and_alloc (size);
7317 gst_buffer_fill (buffer, 0, buf, size);
7318 stream->buffers = g_slist_append (stream->buffers, buffer);
7319 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
7322 GST_WARNING_OBJECT (qtdemux,
7323 "unknown theora cookie %" GST_FOURCC_FORMAT,
7324 GST_FOURCC_ARGS (type));
7333 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
7337 guint32 node_length = 0;
7338 const QtNodeType *type;
7341 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
7343 if (G_UNLIKELY (length < 8))
7344 goto not_enough_data;
7346 node_length = QT_UINT32 (buffer);
7347 fourcc = QT_FOURCC (buffer + 4);
7349 /* ignore empty nodes */
7350 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
7353 type = qtdemux_type_get (fourcc);
7355 end = buffer + length;
7357 GST_LOG_OBJECT (qtdemux,
7358 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
7359 GST_FOURCC_ARGS (fourcc), node_length, type->name);
7361 if (node_length > length)
7362 goto broken_atom_size;
7364 if (type->flags & QT_FLAG_CONTAINER) {
7365 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
7370 if (node_length < 20) {
7371 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
7374 GST_DEBUG_OBJECT (qtdemux,
7375 "parsing stsd (sample table, sample description) atom");
7376 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
7377 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7388 /* also read alac (or whatever) in stead of mp4a in the following,
7389 * since a similar layout is used in other cases as well */
7390 if (fourcc == FOURCC_mp4a)
7392 else if (fourcc == FOURCC_fLaC)
7397 /* There are two things we might encounter here: a true mp4a atom, and
7398 an mp4a entry in an stsd atom. The latter is what we're interested
7399 in, and it looks like an atom, but isn't really one. The true mp4a
7400 atom is short, so we detect it based on length here. */
7401 if (length < min_size) {
7402 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7403 GST_FOURCC_ARGS (fourcc));
7407 /* 'version' here is the sound sample description version. Types 0 and
7408 1 are documented in the QTFF reference, but type 2 is not: it's
7409 described in Apple header files instead (struct SoundDescriptionV2
7411 version = QT_UINT16 (buffer + 16);
7413 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
7414 GST_FOURCC_ARGS (fourcc), version);
7416 /* parse any esds descriptors */
7428 GST_WARNING_OBJECT (qtdemux,
7429 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
7430 GST_FOURCC_ARGS (fourcc), version);
7435 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7461 /* codec_data is contained inside these atoms, which all have
7462 * the same format. */
7463 /* video sample description size is 86 bytes without extension.
7464 * node_length have to be bigger than 86 bytes because video sample
7465 * description can include extenstions such as esds, fiel, glbl, etc. */
7466 if (node_length < 86) {
7467 GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
7468 " sample description length too short (%u < 86)",
7469 GST_FOURCC_ARGS (fourcc), node_length);
7473 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
7474 GST_FOURCC_ARGS (fourcc));
7476 /* version (2 bytes) : this is set to 0, unless a compressor has changed
7478 * revision level (2 bytes) : must be set to 0. */
7479 version = QT_UINT32 (buffer + 16);
7480 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
7482 /* compressor name : PASCAL string and informative purposes
7483 * first byte : the number of bytes to be displayed.
7484 * it has to be less than 32 because it is reserved
7485 * space of 32 bytes total including itself. */
7486 str_len = QT_UINT8 (buffer + 50);
7488 GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
7489 (char *) buffer + 51);
7491 GST_WARNING_OBJECT (qtdemux,
7492 "compressorname length too big (%u > 31)", str_len);
7494 GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
7496 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
7501 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
7502 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
7507 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
7508 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
7509 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7518 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7519 GST_FOURCC_ARGS (fourcc));
7523 version = QT_UINT32 (buffer + 12);
7524 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
7531 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
7536 if (length < offset) {
7537 GST_WARNING_OBJECT (qtdemux,
7538 "skipping too small %" GST_FOURCC_FORMAT " box",
7539 GST_FOURCC_ARGS (fourcc));
7542 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7548 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
7553 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
7558 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
7562 if (!strcmp (type->name, "unknown"))
7563 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
7567 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
7568 GST_FOURCC_ARGS (fourcc));
7574 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7575 (_("This file is corrupt and cannot be played.")),
7576 ("Not enough data for an atom header, got only %u bytes", length));
7581 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7582 (_("This file is corrupt and cannot be played.")),
7583 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
7584 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
7591 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
7595 guint32 child_fourcc;
7597 for (child = g_node_first_child (node); child;
7598 child = g_node_next_sibling (child)) {
7599 buffer = (guint8 *) child->data;
7601 child_fourcc = QT_FOURCC (buffer + 4);
7603 if (G_UNLIKELY (child_fourcc == fourcc)) {
7611 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
7612 GstByteReader * parser)
7616 guint32 child_fourcc, child_len;
7618 for (child = g_node_first_child (node); child;
7619 child = g_node_next_sibling (child)) {
7620 buffer = (guint8 *) child->data;
7622 child_len = QT_UINT32 (buffer);
7623 child_fourcc = QT_FOURCC (buffer + 4);
7625 if (G_UNLIKELY (child_fourcc == fourcc)) {
7626 if (G_UNLIKELY (child_len < (4 + 4)))
7628 /* FIXME: must verify if atom length < parent atom length */
7629 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7637 qtdemux_tree_get_child_by_index (GNode * node, guint index)
7639 return g_node_nth_child (node, index);
7643 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
7644 GstByteReader * parser)
7648 guint32 child_fourcc, child_len;
7650 for (child = g_node_next_sibling (node); child;
7651 child = g_node_next_sibling (child)) {
7652 buffer = (guint8 *) child->data;
7654 child_fourcc = QT_FOURCC (buffer + 4);
7656 if (child_fourcc == fourcc) {
7658 child_len = QT_UINT32 (buffer);
7659 if (G_UNLIKELY (child_len < (4 + 4)))
7661 /* FIXME: must verify if atom length < parent atom length */
7662 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7671 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
7673 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
7677 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
7679 /* FIXME: This can only reliably work if demuxers have a
7680 * separate streaming thread per srcpad. This should be
7681 * done in a demuxer base class, which integrates parts
7684 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
7689 query = gst_query_new_allocation (stream->caps, FALSE);
7691 if (!gst_pad_peer_query (stream->pad, query)) {
7692 /* not a problem, just debug a little */
7693 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
7696 if (stream->allocator)
7697 gst_object_unref (stream->allocator);
7699 if (gst_query_get_n_allocation_params (query) > 0) {
7700 /* try the allocator */
7701 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
7703 stream->use_allocator = TRUE;
7705 stream->allocator = NULL;
7706 gst_allocation_params_init (&stream->params);
7707 stream->use_allocator = FALSE;
7709 gst_query_unref (query);
7714 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
7715 QtDemuxStream * stream)
7718 const gchar *selected_system;
7720 g_return_val_if_fail (qtdemux != NULL, FALSE);
7721 g_return_val_if_fail (stream != NULL, FALSE);
7722 g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1,
7725 if (stream->protection_scheme_type != FOURCC_cenc) {
7726 GST_ERROR_OBJECT (qtdemux, "unsupported protection scheme");
7729 if (qtdemux->protection_system_ids == NULL) {
7730 GST_ERROR_OBJECT (qtdemux, "stream is protected using cenc, but no "
7731 "cenc protection system information has been found");
7734 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
7735 selected_system = gst_protection_select_system ((const gchar **)
7736 qtdemux->protection_system_ids->pdata);
7737 g_ptr_array_remove_index (qtdemux->protection_system_ids,
7738 qtdemux->protection_system_ids->len - 1);
7739 if (!selected_system) {
7740 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
7741 "suitable decryptor element has been found");
7745 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
7746 if (!gst_structure_has_name (s, "application/x-cenc")) {
7747 gst_structure_set (s,
7748 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
7749 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
7751 gst_structure_set_name (s, "application/x-cenc");
7757 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
7759 if (stream->subtype == FOURCC_vide) {
7760 /* fps is calculated base on the duration of the average framerate since
7761 * qt does not have a fixed framerate. */
7762 gboolean fps_available = TRUE;
7764 if ((stream->n_samples == 1) && (stream->first_duration == 0)) {
7766 CUR_STREAM (stream)->fps_n = 0;
7767 CUR_STREAM (stream)->fps_d = 1;
7769 if (stream->duration == 0 || stream->n_samples < 2) {
7770 CUR_STREAM (stream)->fps_n = stream->timescale;
7771 CUR_STREAM (stream)->fps_d = 1;
7772 fps_available = FALSE;
7774 GstClockTime avg_duration;
7778 /* duration and n_samples can be updated for fragmented format
7779 * so, framerate of fragmented format is calculated using data in a moof */
7780 if (qtdemux->fragmented && stream->n_samples_moof > 0
7781 && stream->duration_moof > 0) {
7782 n_samples = stream->n_samples_moof;
7783 duration = stream->duration_moof;
7785 n_samples = stream->n_samples;
7786 duration = stream->duration;
7789 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
7790 /* stream->duration is guint64, timescale, n_samples are guint32 */
7792 gst_util_uint64_scale_round (duration -
7793 stream->first_duration, GST_SECOND,
7794 (guint64) (stream->timescale) * (n_samples - 1));
7796 GST_LOG_OBJECT (qtdemux,
7797 "Calculating avg sample duration based on stream (or moof) duration %"
7799 " minus first sample %u, leaving %d samples gives %"
7800 GST_TIME_FORMAT, duration, stream->first_duration,
7801 n_samples - 1, GST_TIME_ARGS (avg_duration));
7803 gst_video_guess_framerate (avg_duration, &CUR_STREAM (stream)->fps_n,
7804 &CUR_STREAM (stream)->fps_d);
7806 GST_DEBUG_OBJECT (qtdemux,
7807 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
7808 stream->timescale, CUR_STREAM (stream)->fps_n,
7809 CUR_STREAM (stream)->fps_d);
7813 if (CUR_STREAM (stream)->caps) {
7814 CUR_STREAM (stream)->caps =
7815 gst_caps_make_writable (CUR_STREAM (stream)->caps);
7817 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7818 "width", G_TYPE_INT, CUR_STREAM (stream)->width,
7819 "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL);
7821 /* set framerate if calculated framerate is reliable */
7822 if (fps_available) {
7823 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7824 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
7825 CUR_STREAM (stream)->fps_d, NULL);
7828 /* calculate pixel-aspect-ratio using display width and height */
7829 GST_DEBUG_OBJECT (qtdemux,
7830 "video size %dx%d, target display size %dx%d",
7831 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height,
7832 stream->display_width, stream->display_height);
7833 /* qt file might have pasp atom */
7834 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
7835 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w,
7836 CUR_STREAM (stream)->par_h);
7837 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
7838 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
7839 CUR_STREAM (stream)->par_h, NULL);
7840 } else if (stream->display_width > 0 && stream->display_height > 0
7841 && CUR_STREAM (stream)->width > 0
7842 && CUR_STREAM (stream)->height > 0) {
7845 /* calculate the pixel aspect ratio using the display and pixel w/h */
7846 n = stream->display_width * CUR_STREAM (stream)->height;
7847 d = stream->display_height * CUR_STREAM (stream)->width;
7850 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
7851 CUR_STREAM (stream)->par_w = n;
7852 CUR_STREAM (stream)->par_h = d;
7853 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
7854 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
7855 CUR_STREAM (stream)->par_h, NULL);
7858 if (CUR_STREAM (stream)->interlace_mode > 0) {
7859 if (CUR_STREAM (stream)->interlace_mode == 1) {
7860 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
7861 G_TYPE_STRING, "progressive", NULL);
7862 } else if (CUR_STREAM (stream)->interlace_mode == 2) {
7863 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
7864 G_TYPE_STRING, "interleaved", NULL);
7865 if (CUR_STREAM (stream)->field_order == 9) {
7866 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
7867 G_TYPE_STRING, "top-field-first", NULL);
7868 } else if (CUR_STREAM (stream)->field_order == 14) {
7869 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
7870 G_TYPE_STRING, "bottom-field-first", NULL);
7875 /* Create incomplete colorimetry here if needed */
7876 if (CUR_STREAM (stream)->colorimetry.range ||
7877 CUR_STREAM (stream)->colorimetry.matrix ||
7878 CUR_STREAM (stream)->colorimetry.transfer
7879 || CUR_STREAM (stream)->colorimetry.primaries) {
7880 gchar *colorimetry =
7881 gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry);
7882 gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry",
7883 G_TYPE_STRING, colorimetry, NULL);
7884 g_free (colorimetry);
7887 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
7888 guint par_w = 1, par_h = 1;
7890 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
7891 par_w = CUR_STREAM (stream)->par_w;
7892 par_h = CUR_STREAM (stream)->par_h;
7895 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
7896 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w,
7898 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
7901 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7902 "multiview-mode", G_TYPE_STRING,
7903 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
7904 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
7905 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
7910 else if (stream->subtype == FOURCC_soun) {
7911 if (CUR_STREAM (stream)->caps) {
7912 CUR_STREAM (stream)->caps =
7913 gst_caps_make_writable (CUR_STREAM (stream)->caps);
7914 if (CUR_STREAM (stream)->rate > 0)
7915 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7916 "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL);
7917 if (CUR_STREAM (stream)->n_channels > 0)
7918 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7919 "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL);
7920 if (CUR_STREAM (stream)->n_channels > 2) {
7921 /* FIXME: Need to parse the 'chan' atom to get channel layouts
7922 * correctly; this is just the minimum we can do - assume
7923 * we don't actually have any channel positions. */
7924 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7925 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
7931 GstCaps *prev_caps = NULL;
7933 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
7934 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
7935 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
7936 gst_pad_set_active (stream->pad, TRUE);
7938 gst_pad_use_fixed_caps (stream->pad);
7940 if (stream->protected) {
7941 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
7942 GST_ERROR_OBJECT (qtdemux,
7943 "Failed to configure protected stream caps.");
7948 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
7949 CUR_STREAM (stream)->caps);
7950 if (stream->new_stream) {
7953 GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
7956 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
7959 gst_event_parse_stream_flags (event, &stream_flags);
7960 if (gst_event_parse_group_id (event, &qtdemux->group_id))
7961 qtdemux->have_group_id = TRUE;
7963 qtdemux->have_group_id = FALSE;
7964 gst_event_unref (event);
7965 } else if (!qtdemux->have_group_id) {
7966 qtdemux->have_group_id = TRUE;
7967 qtdemux->group_id = gst_util_group_id_next ();
7970 stream->new_stream = FALSE;
7972 gst_pad_create_stream_id_printf (stream->pad,
7973 GST_ELEMENT_CAST (qtdemux), "%03u", stream->track_id);
7974 event = gst_event_new_stream_start (stream_id);
7975 if (qtdemux->have_group_id)
7976 gst_event_set_group_id (event, qtdemux->group_id);
7977 if (stream->disabled)
7978 stream_flags |= GST_STREAM_FLAG_UNSELECT;
7979 if (CUR_STREAM (stream)->sparse) {
7980 stream_flags |= GST_STREAM_FLAG_SPARSE;
7982 stream_flags &= ~GST_STREAM_FLAG_SPARSE;
7984 gst_event_set_stream_flags (event, stream_flags);
7985 gst_pad_push_event (stream->pad, event);
7989 prev_caps = gst_pad_get_current_caps (stream->pad);
7991 if (CUR_STREAM (stream)->caps) {
7993 || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) {
7994 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
7995 CUR_STREAM (stream)->caps);
7996 gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps);
7998 GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
8001 GST_WARNING_OBJECT (qtdemux, "stream without caps");
8005 gst_caps_unref (prev_caps);
8006 stream->new_caps = FALSE;
8012 gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
8013 QtDemuxStream * stream)
8015 if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id)
8018 GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'",
8019 stream->cur_stsd_entry_index, stream->stsd_sample_description_id);
8020 if (G_UNLIKELY (stream->stsd_sample_description_id >=
8021 stream->stsd_entries_length)) {
8022 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
8023 (_("This file is invalid and cannot be played.")),
8024 ("New sample description id is out of bounds (%d >= %d)",
8025 stream->stsd_sample_description_id, stream->stsd_entries_length));
8027 stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
8028 stream->new_caps = TRUE;
8033 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
8034 QtDemuxStream * stream, GstTagList * list)
8036 gboolean ret = TRUE;
8037 /* consistent default for push based mode */
8038 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
8040 if (stream->subtype == FOURCC_vide) {
8041 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8044 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8047 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8048 gst_object_unref (stream->pad);
8054 qtdemux->n_video_streams++;
8055 } else if (stream->subtype == FOURCC_soun) {
8056 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
8059 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
8061 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8062 gst_object_unref (stream->pad);
8067 qtdemux->n_audio_streams++;
8068 } else if (stream->subtype == FOURCC_strm) {
8069 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
8070 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
8071 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
8072 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
8075 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
8077 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8078 gst_object_unref (stream->pad);
8083 qtdemux->n_sub_streams++;
8084 } else if (CUR_STREAM (stream)->caps) {
8085 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8088 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8090 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8091 gst_object_unref (stream->pad);
8096 qtdemux->n_video_streams++;
8098 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
8105 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
8106 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
8107 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
8108 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
8110 if (stream->stream_tags)
8111 gst_tag_list_unref (stream->stream_tags);
8112 stream->stream_tags = list;
8114 /* global tags go on each pad anyway */
8115 stream->send_global_tags = TRUE;
8116 /* send upstream GST_EVENT_PROTECTION events that were received before
8117 this source pad was created */
8118 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
8119 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
8123 gst_tag_list_unref (list);
8127 /* find next atom with @fourcc starting at @offset */
8128 static GstFlowReturn
8129 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
8130 guint64 * length, guint32 fourcc)
8136 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
8137 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
8143 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
8144 if (G_UNLIKELY (ret != GST_FLOW_OK))
8146 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
8149 gst_buffer_unref (buf);
8152 gst_buffer_map (buf, &map, GST_MAP_READ);
8153 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
8154 gst_buffer_unmap (buf, &map);
8155 gst_buffer_unref (buf);
8157 if (G_UNLIKELY (*length == 0)) {
8158 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
8159 ret = GST_FLOW_ERROR;
8163 if (lfourcc == fourcc) {
8164 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
8168 GST_LOG_OBJECT (qtdemux,
8169 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
8170 GST_FOURCC_ARGS (fourcc), *offset);
8179 /* might simply have had last one */
8180 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
8185 /* should only do something in pull mode */
8186 /* call with OBJECT lock */
8187 static GstFlowReturn
8188 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
8190 guint64 length, offset;
8191 GstBuffer *buf = NULL;
8192 GstFlowReturn ret = GST_FLOW_OK;
8193 GstFlowReturn res = GST_FLOW_OK;
8196 offset = qtdemux->moof_offset;
8197 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
8200 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8201 return GST_FLOW_EOS;
8204 /* best not do pull etc with lock held */
8205 GST_OBJECT_UNLOCK (qtdemux);
8207 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8208 if (ret != GST_FLOW_OK)
8211 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
8212 if (G_UNLIKELY (ret != GST_FLOW_OK))
8214 gst_buffer_map (buf, &map, GST_MAP_READ);
8215 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
8216 gst_buffer_unmap (buf, &map);
8217 gst_buffer_unref (buf);
8222 gst_buffer_unmap (buf, &map);
8223 gst_buffer_unref (buf);
8227 /* look for next moof */
8228 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8229 if (G_UNLIKELY (ret != GST_FLOW_OK))
8233 GST_OBJECT_LOCK (qtdemux);
8235 qtdemux->moof_offset = offset;
8241 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
8243 res = GST_FLOW_ERROR;
8248 /* maybe upstream temporarily flushing */
8249 if (ret != GST_FLOW_FLUSHING) {
8250 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8253 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
8254 /* resume at current position next time */
8261 /* initialise bytereaders for stbl sub-atoms */
8263 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
8265 stream->stbl_index = -1; /* no samples have yet been parsed */
8266 stream->sample_index = -1;
8268 /* time-to-sample atom */
8269 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
8272 /* copy atom data into a new buffer for later use */
8273 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
8275 /* skip version + flags */
8276 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
8277 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
8279 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
8281 /* make sure there's enough data */
8282 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
8283 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
8284 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
8285 stream->n_sample_times);
8286 if (!stream->n_sample_times)
8290 /* sync sample atom */
8291 stream->stps_present = FALSE;
8292 if ((stream->stss_present =
8293 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
8294 &stream->stss) ? TRUE : FALSE) == TRUE) {
8295 /* copy atom data into a new buffer for later use */
8296 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
8298 /* skip version + flags */
8299 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
8300 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
8303 if (stream->n_sample_syncs) {
8304 /* make sure there's enough data */
8305 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
8309 /* partial sync sample atom */
8310 if ((stream->stps_present =
8311 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
8312 &stream->stps) ? TRUE : FALSE) == TRUE) {
8313 /* copy atom data into a new buffer for later use */
8314 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
8316 /* skip version + flags */
8317 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
8318 !gst_byte_reader_get_uint32_be (&stream->stps,
8319 &stream->n_sample_partial_syncs))
8322 /* if there are no entries, the stss table contains the real
8324 if (stream->n_sample_partial_syncs) {
8325 /* make sure there's enough data */
8326 if (!qt_atom_parser_has_chunks (&stream->stps,
8327 stream->n_sample_partial_syncs, 4))
8334 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
8337 /* copy atom data into a new buffer for later use */
8338 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
8340 /* skip version + flags */
8341 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
8342 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
8345 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
8348 if (!stream->n_samples)
8351 /* sample-to-chunk atom */
8352 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
8355 /* copy atom data into a new buffer for later use */
8356 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
8358 /* skip version + flags */
8359 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
8360 !gst_byte_reader_get_uint32_be (&stream->stsc,
8361 &stream->n_samples_per_chunk))
8364 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
8365 stream->n_samples_per_chunk);
8367 /* make sure there's enough data */
8368 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
8374 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
8375 stream->co_size = sizeof (guint32);
8376 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
8378 stream->co_size = sizeof (guint64);
8382 /* copy atom data into a new buffer for later use */
8383 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
8385 /* skip version + flags */
8386 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
8389 /* chunks_are_samples == TRUE means treat chunks as samples */
8390 stream->chunks_are_samples = stream->sample_size
8391 && !CUR_STREAM (stream)->sampled;
8392 if (stream->chunks_are_samples) {
8393 /* treat chunks as samples */
8394 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
8397 /* skip number of entries */
8398 if (!gst_byte_reader_skip (&stream->stco, 4))
8401 /* make sure there are enough data in the stsz atom */
8402 if (!stream->sample_size) {
8403 /* different sizes for each sample */
8404 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
8409 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
8410 stream->n_samples, (guint) sizeof (QtDemuxSample),
8411 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
8413 if (stream->n_samples >=
8414 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
8415 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
8416 "be larger than %uMB (broken file?)", stream->n_samples,
8417 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
8421 g_assert (stream->samples == NULL);
8422 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
8423 if (!stream->samples) {
8424 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
8429 /* composition time-to-sample */
8430 if ((stream->ctts_present =
8431 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
8432 &stream->ctts) ? TRUE : FALSE) == TRUE) {
8433 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
8435 /* copy atom data into a new buffer for later use */
8436 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
8438 /* skip version + flags */
8439 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
8440 || !gst_byte_reader_get_uint32_be (&stream->ctts,
8441 &stream->n_composition_times))
8444 /* make sure there's enough data */
8445 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
8449 /* This is optional, if missing we iterate the ctts */
8450 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
8451 if (!gst_byte_reader_skip (&cslg, 1 + 3)
8452 || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
8453 g_free ((gpointer) cslg.data);
8457 gint32 cslg_least = 0;
8458 guint num_entries, pos;
8461 pos = gst_byte_reader_get_pos (&stream->ctts);
8462 num_entries = stream->n_composition_times;
8464 stream->cslg_shift = 0;
8466 for (i = 0; i < num_entries; i++) {
8469 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
8470 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8472 if (offset < cslg_least)
8473 cslg_least = offset;
8477 stream->cslg_shift = ABS (cslg_least);
8479 stream->cslg_shift = 0;
8481 /* reset the reader so we can generate sample table */
8482 gst_byte_reader_set_pos (&stream->ctts, pos);
8485 /* Ensure the cslg_shift value is consistent so we can use it
8486 * unconditionnally to produce TS and Segment */
8487 stream->cslg_shift = 0;
8494 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8495 (_("This file is corrupt and cannot be played.")), (NULL));
8500 gst_qtdemux_stbl_free (stream);
8501 if (!qtdemux->fragmented) {
8502 /* not quite good */
8503 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
8506 /* may pick up samples elsewhere */
8512 /* collect samples from the next sample to be parsed up to sample @n for @stream
8513 * by reading the info from @stbl
8515 * This code can be executed from both the streaming thread and the seeking
8516 * thread so it takes the object lock to protect itself
8519 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
8522 QtDemuxSample *samples, *first, *cur, *last;
8523 guint32 n_samples_per_chunk;
8526 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
8527 GST_FOURCC_FORMAT ", pad %s",
8528 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
8529 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
8531 n_samples = stream->n_samples;
8534 goto out_of_samples;
8536 GST_OBJECT_LOCK (qtdemux);
8537 if (n <= stream->stbl_index)
8538 goto already_parsed;
8540 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
8542 if (!stream->stsz.data) {
8543 /* so we already parsed and passed all the moov samples;
8544 * onto fragmented ones */
8545 g_assert (qtdemux->fragmented);
8549 /* pointer to the sample table */
8550 samples = stream->samples;
8552 /* starts from -1, moves to the next sample index to parse */
8553 stream->stbl_index++;
8555 /* keep track of the first and last sample to fill */
8556 first = &samples[stream->stbl_index];
8559 if (!stream->chunks_are_samples) {
8560 /* set the sample sizes */
8561 if (stream->sample_size == 0) {
8562 /* different sizes for each sample */
8563 for (cur = first; cur <= last; cur++) {
8564 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
8565 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
8566 (guint) (cur - samples), cur->size);
8569 /* samples have the same size */
8570 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
8571 for (cur = first; cur <= last; cur++)
8572 cur->size = stream->sample_size;
8576 n_samples_per_chunk = stream->n_samples_per_chunk;
8579 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
8582 if (stream->stsc_chunk_index >= stream->last_chunk
8583 || stream->stsc_chunk_index < stream->first_chunk) {
8584 stream->first_chunk =
8585 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8586 stream->samples_per_chunk =
8587 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8589 stream->stsd_sample_description_id =
8590 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
8592 /* chunk numbers are counted from 1 it seems */
8593 if (G_UNLIKELY (stream->first_chunk == 0))
8596 --stream->first_chunk;
8598 /* the last chunk of each entry is calculated by taking the first chunk
8599 * of the next entry; except if there is no next, where we fake it with
8601 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
8602 stream->last_chunk = G_MAXUINT32;
8604 stream->last_chunk =
8605 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
8606 if (G_UNLIKELY (stream->last_chunk == 0))
8609 --stream->last_chunk;
8612 GST_LOG_OBJECT (qtdemux,
8613 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
8614 "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
8615 stream->samples_per_chunk, stream->stsd_sample_description_id);
8617 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
8620 if (stream->last_chunk != G_MAXUINT32) {
8621 if (!qt_atom_parser_peek_sub (&stream->stco,
8622 stream->first_chunk * stream->co_size,
8623 (stream->last_chunk - stream->first_chunk) * stream->co_size,
8628 stream->co_chunk = stream->stco;
8629 if (!gst_byte_reader_skip (&stream->co_chunk,
8630 stream->first_chunk * stream->co_size))
8634 stream->stsc_chunk_index = stream->first_chunk;
8637 last_chunk = stream->last_chunk;
8639 if (stream->chunks_are_samples) {
8640 cur = &samples[stream->stsc_chunk_index];
8642 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8645 stream->stsc_chunk_index = j;
8650 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
8653 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
8654 "%" G_GUINT64_FORMAT, j, cur->offset);
8656 if (CUR_STREAM (stream)->samples_per_frame > 0 &&
8657 CUR_STREAM (stream)->bytes_per_frame > 0) {
8659 (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
8660 CUR_STREAM (stream)->samples_per_frame *
8661 CUR_STREAM (stream)->bytes_per_frame;
8663 cur->size = stream->samples_per_chunk;
8666 GST_DEBUG_OBJECT (qtdemux,
8667 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
8668 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
8669 stream->stco_sample_index)), cur->size);
8671 cur->timestamp = stream->stco_sample_index;
8672 cur->duration = stream->samples_per_chunk;
8673 cur->keyframe = TRUE;
8676 stream->stco_sample_index += stream->samples_per_chunk;
8678 stream->stsc_chunk_index = j;
8680 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8681 guint32 samples_per_chunk;
8682 guint64 chunk_offset;
8684 if (!stream->stsc_sample_index
8685 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
8686 &stream->chunk_offset))
8689 samples_per_chunk = stream->samples_per_chunk;
8690 chunk_offset = stream->chunk_offset;
8692 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
8693 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
8694 G_GUINT64_FORMAT " and size %d",
8695 (guint) (cur - samples), chunk_offset, cur->size);
8697 cur->offset = chunk_offset;
8698 chunk_offset += cur->size;
8701 if (G_UNLIKELY (cur > last)) {
8703 stream->stsc_sample_index = k + 1;
8704 stream->chunk_offset = chunk_offset;
8705 stream->stsc_chunk_index = j;
8709 stream->stsc_sample_index = 0;
8711 stream->stsc_chunk_index = j;
8713 stream->stsc_index++;
8716 if (stream->chunks_are_samples)
8720 guint32 n_sample_times;
8722 n_sample_times = stream->n_sample_times;
8725 for (i = stream->stts_index; i < n_sample_times; i++) {
8726 guint32 stts_samples;
8727 gint32 stts_duration;
8730 if (stream->stts_sample_index >= stream->stts_samples
8731 || !stream->stts_sample_index) {
8733 stream->stts_samples =
8734 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8735 stream->stts_duration =
8736 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8738 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
8739 i, stream->stts_samples, stream->stts_duration);
8741 stream->stts_sample_index = 0;
8744 stts_samples = stream->stts_samples;
8745 stts_duration = stream->stts_duration;
8746 stts_time = stream->stts_time;
8748 for (j = stream->stts_sample_index; j < stts_samples; j++) {
8749 GST_DEBUG_OBJECT (qtdemux,
8750 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
8751 (guint) (cur - samples), j,
8752 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
8754 cur->timestamp = stts_time;
8755 cur->duration = stts_duration;
8757 /* avoid 32-bit wrap-around,
8758 * but still mind possible 'negative' duration */
8759 stts_time += (gint64) stts_duration;
8762 if (G_UNLIKELY (cur > last)) {
8764 stream->stts_time = stts_time;
8765 stream->stts_sample_index = j + 1;
8766 if (stream->stts_sample_index >= stream->stts_samples)
8767 stream->stts_index++;
8771 stream->stts_sample_index = 0;
8772 stream->stts_time = stts_time;
8773 stream->stts_index++;
8775 /* fill up empty timestamps with the last timestamp, this can happen when
8776 * the last samples do not decode and so we don't have timestamps for them.
8777 * We however look at the last timestamp to estimate the track length so we
8778 * need something in here. */
8779 for (; cur < last; cur++) {
8780 GST_DEBUG_OBJECT (qtdemux,
8781 "fill sample %d: timestamp %" GST_TIME_FORMAT,
8782 (guint) (cur - samples),
8783 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
8784 cur->timestamp = stream->stts_time;
8790 /* sample sync, can be NULL */
8791 if (stream->stss_present == TRUE) {
8792 guint32 n_sample_syncs;
8794 n_sample_syncs = stream->n_sample_syncs;
8796 if (!n_sample_syncs) {
8797 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
8798 stream->all_keyframe = TRUE;
8800 for (i = stream->stss_index; i < n_sample_syncs; i++) {
8801 /* note that the first sample is index 1, not 0 */
8804 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
8806 if (G_LIKELY (index > 0 && index <= n_samples)) {
8808 samples[index].keyframe = TRUE;
8809 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8810 /* and exit if we have enough samples */
8811 if (G_UNLIKELY (index >= n)) {
8818 stream->stss_index = i;
8821 /* stps marks partial sync frames like open GOP I-Frames */
8822 if (stream->stps_present == TRUE) {
8823 guint32 n_sample_partial_syncs;
8825 n_sample_partial_syncs = stream->n_sample_partial_syncs;
8827 /* if there are no entries, the stss table contains the real
8829 if (n_sample_partial_syncs) {
8830 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
8831 /* note that the first sample is index 1, not 0 */
8834 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
8836 if (G_LIKELY (index > 0 && index <= n_samples)) {
8838 samples[index].keyframe = TRUE;
8839 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8840 /* and exit if we have enough samples */
8841 if (G_UNLIKELY (index >= n)) {
8848 stream->stps_index = i;
8852 /* no stss, all samples are keyframes */
8853 stream->all_keyframe = TRUE;
8854 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
8859 /* composition time to sample */
8860 if (stream->ctts_present == TRUE) {
8861 guint32 n_composition_times;
8863 gint32 ctts_soffset;
8865 /* Fill in the pts_offsets */
8867 n_composition_times = stream->n_composition_times;
8869 for (i = stream->ctts_index; i < n_composition_times; i++) {
8870 if (stream->ctts_sample_index >= stream->ctts_count
8871 || !stream->ctts_sample_index) {
8872 stream->ctts_count =
8873 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
8874 stream->ctts_soffset =
8875 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8876 stream->ctts_sample_index = 0;
8879 ctts_count = stream->ctts_count;
8880 ctts_soffset = stream->ctts_soffset;
8882 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
8883 cur->pts_offset = ctts_soffset;
8886 if (G_UNLIKELY (cur > last)) {
8888 stream->ctts_sample_index = j + 1;
8892 stream->ctts_sample_index = 0;
8893 stream->ctts_index++;
8897 stream->stbl_index = n;
8898 /* if index has been completely parsed, free data that is no-longer needed */
8899 if (n + 1 == stream->n_samples) {
8900 gst_qtdemux_stbl_free (stream);
8901 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
8902 if (qtdemux->pullbased) {
8903 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
8904 while (n + 1 == stream->n_samples)
8905 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
8909 GST_OBJECT_UNLOCK (qtdemux);
8916 GST_LOG_OBJECT (qtdemux,
8917 "Tried to parse up to sample %u but this sample has already been parsed",
8919 /* if fragmented, there may be more */
8920 if (qtdemux->fragmented && n == stream->stbl_index)
8922 GST_OBJECT_UNLOCK (qtdemux);
8928 GST_LOG_OBJECT (qtdemux,
8929 "Tried to parse up to sample %u but there are only %u samples", n + 1,
8931 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8932 (_("This file is corrupt and cannot be played.")), (NULL));
8937 GST_OBJECT_UNLOCK (qtdemux);
8938 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8939 (_("This file is corrupt and cannot be played.")), (NULL));
8944 /* collect all segment info for @stream.
8947 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
8951 /* accept edts if they contain gaps at start and there is only
8952 * one media segment */
8953 gboolean allow_pushbased_edts = TRUE;
8954 gint media_segments_count = 0;
8956 /* parse and prepare segment info from the edit list */
8957 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
8958 stream->n_segments = 0;
8959 stream->segments = NULL;
8960 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
8963 gint i, count, entry_size;
8966 const guint8 *buffer;
8970 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
8971 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
8974 buffer = elst->data;
8976 size = QT_UINT32 (buffer);
8977 /* version, flags, n_segments */
8979 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
8982 version = QT_UINT8 (buffer + 8);
8983 entry_size = (version == 1) ? 20 : 12;
8985 n_segments = QT_UINT32 (buffer + 12);
8987 if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
8988 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
8992 /* we might allocate a bit too much, at least allocate 1 segment */
8993 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
8995 /* segments always start from 0 */
9000 for (i = 0; i < n_segments; i++) {
9003 gboolean time_valid = TRUE;
9004 QtDemuxSegment *segment;
9006 GstClockTime media_start = GST_CLOCK_TIME_NONE;
9009 media_time = QT_UINT64 (buffer + 8);
9010 duration = QT_UINT64 (buffer);
9011 if (media_time == G_MAXUINT64)
9014 media_time = QT_UINT32 (buffer + 4);
9015 duration = QT_UINT32 (buffer);
9016 if (media_time == G_MAXUINT32)
9021 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
9023 segment = &stream->segments[count++];
9025 /* time and duration expressed in global timescale */
9026 segment->time = stime;
9027 /* add non scaled values so we don't cause roundoff errors */
9028 if (duration || media_start == GST_CLOCK_TIME_NONE) {
9030 stime = QTTIME_TO_GSTTIME (qtdemux, time);
9031 segment->duration = stime - segment->time;
9033 /* zero duration does not imply media_start == media_stop
9034 * but, only specify media_start.*/
9035 stime = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
9036 if (GST_CLOCK_TIME_IS_VALID (stime) && time_valid
9037 && stime >= media_start) {
9038 segment->duration = stime - media_start;
9040 segment->duration = GST_CLOCK_TIME_NONE;
9043 segment->stop_time = stime;
9045 segment->trak_media_start = media_time;
9046 /* media_time expressed in stream timescale */
9048 segment->media_start = media_start;
9049 segment->media_stop = segment->media_start + segment->duration;
9050 media_segments_count++;
9052 segment->media_start = GST_CLOCK_TIME_NONE;
9053 segment->media_stop = GST_CLOCK_TIME_NONE;
9055 rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
9057 if (rate_int <= 1) {
9058 /* 0 is not allowed, some programs write 1 instead of the floating point
9060 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
9064 segment->rate = rate_int / 65536.0;
9067 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
9068 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
9069 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
9070 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
9071 i, GST_TIME_ARGS (segment->time),
9072 GST_TIME_ARGS (segment->duration),
9073 GST_TIME_ARGS (segment->media_start), media_time,
9074 GST_TIME_ARGS (segment->media_stop),
9075 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
9077 if (segment->stop_time > qtdemux->segment.stop) {
9078 GST_WARNING_OBJECT (qtdemux, "Segment %d "
9079 " extends to %" GST_TIME_FORMAT
9080 " past the end of the file duration %" GST_TIME_FORMAT
9081 " it will be truncated", i, GST_TIME_ARGS (segment->stop_time),
9082 GST_TIME_ARGS (qtdemux->segment.stop));
9083 qtdemux->segment.stop = segment->stop_time;
9086 buffer += entry_size;
9088 GST_DEBUG_OBJECT (qtdemux, "found %d segments", count);
9089 stream->n_segments = count;
9090 if (media_segments_count != 1)
9091 allow_pushbased_edts = FALSE;
9095 /* push based does not handle segments, so act accordingly here,
9096 * and warn if applicable */
9097 if (!qtdemux->pullbased && !allow_pushbased_edts) {
9098 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
9099 /* remove and use default one below, we stream like it anyway */
9100 g_free (stream->segments);
9101 stream->segments = NULL;
9102 stream->n_segments = 0;
9105 /* no segments, create one to play the complete trak */
9106 if (stream->n_segments == 0) {
9107 GstClockTime stream_duration =
9108 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
9110 if (stream->segments == NULL)
9111 stream->segments = g_new (QtDemuxSegment, 1);
9113 /* represent unknown our way */
9114 if (stream_duration == 0)
9115 stream_duration = GST_CLOCK_TIME_NONE;
9117 stream->segments[0].time = 0;
9118 stream->segments[0].stop_time = stream_duration;
9119 stream->segments[0].duration = stream_duration;
9120 stream->segments[0].media_start = 0;
9121 stream->segments[0].media_stop = stream_duration;
9122 stream->segments[0].rate = 1.0;
9123 stream->segments[0].trak_media_start = 0;
9125 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
9126 GST_TIME_ARGS (stream_duration));
9127 stream->n_segments = 1;
9128 stream->dummy_segment = TRUE;
9130 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
9136 * Parses the stsd atom of a svq3 trak looking for
9137 * the SMI and gama atoms.
9140 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
9141 const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
9143 const guint8 *_gamma = NULL;
9144 GstBuffer *_seqh = NULL;
9145 const guint8 *stsd_data = stsd_entry_data;
9146 guint32 length = QT_UINT32 (stsd_data);
9150 GST_WARNING_OBJECT (qtdemux, "stsd too short");
9156 version = QT_UINT16 (stsd_data);
9161 while (length > 8) {
9162 guint32 fourcc, size;
9164 size = QT_UINT32 (stsd_data);
9165 fourcc = QT_FOURCC (stsd_data + 4);
9166 data = stsd_data + 8;
9169 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
9170 "svq3 atom parsing");
9179 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
9180 " for gama atom, expected 12", size);
9185 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
9187 if (_seqh != NULL) {
9188 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
9189 " found, ignoring");
9191 seqh_size = QT_UINT32 (data + 4);
9192 if (seqh_size > 0) {
9193 _seqh = gst_buffer_new_and_alloc (seqh_size);
9194 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
9201 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
9202 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
9206 if (size <= length) {
9212 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
9215 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
9216 G_GUINT16_FORMAT, version);
9227 gst_buffer_unref (_seqh);
9232 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
9239 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
9240 * atom that might contain a 'data' atom with the rtsp uri.
9241 * This case was reported in bug #597497, some info about
9242 * the hndl atom can be found in TN1195
9244 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
9245 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
9248 guint32 dref_num_entries = 0;
9249 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
9250 gst_byte_reader_skip (&dref, 4) &&
9251 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
9254 /* search dref entries for hndl atom */
9255 for (i = 0; i < dref_num_entries; i++) {
9256 guint32 size = 0, type;
9257 guint8 string_len = 0;
9258 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
9259 qt_atom_parser_get_fourcc (&dref, &type)) {
9260 if (type == FOURCC_hndl) {
9261 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
9263 /* skip data reference handle bytes and the
9264 * following pascal string and some extra 4
9265 * bytes I have no idea what are */
9266 if (!gst_byte_reader_skip (&dref, 4) ||
9267 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
9268 !gst_byte_reader_skip (&dref, string_len + 4)) {
9269 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
9273 /* iterate over the atoms to find the data atom */
9274 while (gst_byte_reader_get_remaining (&dref) >= 8) {
9278 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
9279 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
9280 if (atom_type == FOURCC_data) {
9281 const guint8 *uri_aux = NULL;
9283 /* found the data atom that might contain the rtsp uri */
9284 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
9285 "hndl atom, interpreting it as an URI");
9286 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
9288 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
9289 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
9291 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
9292 "didn't contain a rtsp address");
9294 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
9299 /* skipping to the next entry */
9300 if (!gst_byte_reader_skip (&dref, atom_size - 8))
9303 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
9310 /* skip to the next entry */
9311 if (!gst_byte_reader_skip (&dref, size - 8))
9314 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
9317 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
9323 #define AMR_NB_ALL_MODES 0x81ff
9324 #define AMR_WB_ALL_MODES 0x83ff
9326 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
9328 /* The 'damr' atom is of the form:
9330 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
9331 * 32 b 8 b 16 b 8 b 8 b
9333 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
9334 * represents the highest mode used in the stream (and thus the maximum
9335 * bitrate), with a couple of special cases as seen below.
9338 /* Map of frame type ID -> bitrate */
9339 static const guint nb_bitrates[] = {
9340 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
9342 static const guint wb_bitrates[] = {
9343 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
9349 gst_buffer_map (buf, &map, GST_MAP_READ);
9351 if (map.size != 0x11) {
9352 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
9356 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
9357 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
9358 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
9362 mode_set = QT_UINT16 (map.data + 13);
9364 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
9365 max_mode = 7 + (wb ? 1 : 0);
9367 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
9368 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
9370 if (max_mode == -1) {
9371 GST_DEBUG ("No mode indication was found (mode set) = %x",
9376 gst_buffer_unmap (buf, &map);
9377 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
9380 gst_buffer_unmap (buf, &map);
9385 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
9386 GstByteReader * reader, guint32 * matrix, const gchar * atom)
9389 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
9395 if (gst_byte_reader_get_remaining (reader) < 36)
9398 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
9399 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
9400 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
9401 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
9402 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
9403 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
9404 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
9405 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
9406 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
9408 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
9409 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
9410 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
9412 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
9413 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
9415 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
9416 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
9423 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
9424 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
9431 * This macro will only compare value abdegh, it expects cfi to have already
9434 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
9435 (m)[3] == (d << 16) && (m)[4] == (e << 16))
9437 /* only handle the cases where the last column has standard values */
9438 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
9439 const gchar *rotation_tag = NULL;
9441 /* no rotation needed */
9442 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
9444 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
9445 rotation_tag = "rotate-90";
9446 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
9447 rotation_tag = "rotate-180";
9448 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
9449 rotation_tag = "rotate-270";
9451 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9454 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
9456 if (rotation_tag != NULL) {
9457 if (*taglist == NULL)
9458 *taglist = gst_tag_list_new_empty ();
9459 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
9460 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
9463 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9467 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
9468 * protected streams (sinf, frma, schm and schi); if the protection scheme is
9469 * Common Encryption (cenc), the function will also parse the tenc box (defined
9470 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
9471 * (typically an enc[v|a|t|s] sample entry); the function will set
9472 * @original_fmt to the fourcc of the original unencrypted stream format.
9473 * Returns TRUE if successful; FALSE otherwise. */
9475 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
9476 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
9483 g_return_val_if_fail (qtdemux != NULL, FALSE);
9484 g_return_val_if_fail (stream != NULL, FALSE);
9485 g_return_val_if_fail (container != NULL, FALSE);
9486 g_return_val_if_fail (original_fmt != NULL, FALSE);
9488 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
9489 if (G_UNLIKELY (!sinf)) {
9490 if (stream->protection_scheme_type == FOURCC_cenc) {
9491 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
9492 "mandatory for Common Encryption");
9498 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
9499 if (G_UNLIKELY (!frma)) {
9500 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
9504 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
9505 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
9506 GST_FOURCC_ARGS (*original_fmt));
9508 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
9510 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
9513 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
9514 stream->protection_scheme_version =
9515 QT_UINT32 ((const guint8 *) schm->data + 16);
9517 GST_DEBUG_OBJECT (qtdemux,
9518 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
9519 "protection_scheme_version: %#010x",
9520 GST_FOURCC_ARGS (stream->protection_scheme_type),
9521 stream->protection_scheme_version);
9523 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
9525 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
9528 if (stream->protection_scheme_type == FOURCC_cenc) {
9529 QtDemuxCencSampleSetInfo *info;
9531 const guint8 *tenc_data;
9532 guint32 isEncrypted;
9534 const guint8 *default_kid;
9537 if (G_UNLIKELY (!stream->protection_scheme_info))
9538 stream->protection_scheme_info =
9539 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
9541 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
9543 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
9545 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
9546 "which is mandatory for Common Encryption");
9549 tenc_data = (const guint8 *) tenc->data + 12;
9550 isEncrypted = QT_UINT24 (tenc_data);
9551 iv_size = QT_UINT8 (tenc_data + 3);
9552 default_kid = (tenc_data + 4);
9553 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
9554 gst_buffer_fill (kid_buf, 0, default_kid, 16);
9555 if (info->default_properties)
9556 gst_structure_free (info->default_properties);
9557 info->default_properties =
9558 gst_structure_new ("application/x-cenc",
9559 "iv_size", G_TYPE_UINT, iv_size,
9560 "encrypted", G_TYPE_BOOLEAN, (isEncrypted == 1),
9561 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
9562 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
9563 "is_encrypted=%u, iv_size=%u", isEncrypted, iv_size);
9564 gst_buffer_unref (kid_buf);
9570 * With each track we associate a new QtDemuxStream that contains all the info
9572 * traks that do not decode to something (like strm traks) will not have a pad.
9575 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
9596 QtDemuxStream *stream = NULL;
9597 gboolean new_stream = FALSE;
9598 gchar *codec = NULL;
9599 const guint8 *stsd_data;
9600 const guint8 *stsd_entry_data;
9601 guint remaining_stsd_len;
9602 guint stsd_entry_count;
9604 guint16 lang_code; /* quicktime lang code or packed iso code */
9606 guint32 tkhd_flags = 0;
9607 guint8 tkhd_version = 0;
9608 guint32 w = 0, h = 0;
9610 guint value_size, stsd_len, len;
9614 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
9616 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
9617 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
9618 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
9621 /* pick between 64 or 32 bits */
9622 value_size = tkhd_version == 1 ? 8 : 4;
9623 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
9624 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
9627 if (!qtdemux->got_moov) {
9628 if (qtdemux_find_stream (qtdemux, track_id))
9629 goto existing_stream;
9630 stream = _create_stream ();
9631 stream->track_id = track_id;
9634 stream = qtdemux_find_stream (qtdemux, track_id);
9636 GST_WARNING_OBJECT (qtdemux, "Stream not found, going to ignore it");
9640 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
9642 /* flush samples data from this track from previous moov */
9643 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
9644 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
9646 /* need defaults for fragments */
9647 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
9649 if ((tkhd_flags & 1) == 0)
9650 stream->disabled = TRUE;
9652 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
9653 tkhd_version, tkhd_flags, stream->track_id);
9655 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
9658 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
9659 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
9660 if (qtdemux->major_brand != FOURCC_mjp2 ||
9661 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
9665 len = QT_UINT32 ((guint8 *) mdhd->data);
9666 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
9667 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
9668 if (version == 0x01000000) {
9671 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
9672 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
9673 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
9677 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
9678 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
9679 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
9682 if (lang_code < 0x400) {
9683 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
9684 } else if (lang_code == 0x7fff) {
9685 stream->lang_id[0] = 0; /* unspecified */
9687 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
9688 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
9689 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
9690 stream->lang_id[3] = 0;
9693 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
9695 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
9697 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
9698 lang_code, stream->lang_id);
9700 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
9703 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
9704 /* chapters track reference */
9705 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
9707 gsize length = GST_READ_UINT32_BE (chap->data);
9708 if (qtdemux->chapters_track_id)
9709 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
9712 qtdemux->chapters_track_id =
9713 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
9718 /* fragmented files may have bogus duration in moov */
9719 if (!qtdemux->fragmented &&
9720 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
9721 guint64 tdur1, tdur2;
9723 /* don't overflow */
9724 tdur1 = stream->timescale * (guint64) qtdemux->duration;
9725 tdur2 = qtdemux->timescale * (guint64) stream->duration;
9728 * some of those trailers, nowadays, have prologue images that are
9729 * themselves video tracks as well. I haven't really found a way to
9730 * identify those yet, except for just looking at their duration. */
9731 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
9732 GST_WARNING_OBJECT (qtdemux,
9733 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
9734 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
9735 "found, assuming preview image or something; skipping track",
9736 stream->duration, stream->timescale, qtdemux->duration,
9737 qtdemux->timescale);
9739 gst_qtdemux_stream_free (qtdemux, stream);
9744 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
9747 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
9748 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
9750 len = QT_UINT32 ((guint8 *) hdlr->data);
9752 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
9753 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
9754 GST_FOURCC_ARGS (stream->subtype));
9756 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
9759 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
9762 /*parse svmi header if existing */
9763 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
9765 len = QT_UINT32 ((guint8 *) svmi->data);
9766 version = QT_UINT32 ((guint8 *) svmi->data + 8);
9768 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
9769 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
9770 guint8 frame_type, frame_layout;
9772 /* MPEG-A stereo video */
9773 if (qtdemux->major_brand == FOURCC_ss02)
9774 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
9776 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
9777 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
9778 switch (frame_type) {
9780 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
9783 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
9786 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
9789 /* mode 3 is primary/secondary view sequence, ie
9790 * left/right views in separate tracks. See section 7.2
9791 * of ISO/IEC 23000-11:2009 */
9792 GST_FIXME_OBJECT (qtdemux,
9793 "Implement stereo video in separate streams");
9796 if ((frame_layout & 0x1) == 0)
9797 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
9799 GST_LOG_OBJECT (qtdemux,
9800 "StereoVideo: composition type: %u, is_left_first: %u",
9801 frame_type, frame_layout);
9802 stream->multiview_mode = mode;
9803 stream->multiview_flags = flags;
9807 /* parse rest of tkhd */
9808 if (stream->subtype == FOURCC_vide) {
9811 /* version 1 uses some 64-bit ints */
9812 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
9815 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
9818 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
9819 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
9822 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
9823 &stream->stream_tags);
9827 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
9829 stsd_data = (const guint8 *) stsd->data;
9831 /* stsd should at least have one entry */
9832 stsd_len = QT_UINT32 (stsd_data);
9833 if (stsd_len < 24) {
9834 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
9835 if (stream->subtype == FOURCC_vivo) {
9837 gst_qtdemux_stream_free (qtdemux, stream);
9844 stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
9845 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
9846 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
9847 GST_LOG_OBJECT (qtdemux, "stsd entry count: %u", stsd_entry_count);
9849 stsd_entry_data = stsd_data + 16;
9850 remaining_stsd_len = stsd_len - 16;
9851 for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
9852 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
9854 /* and that entry should fit within stsd */
9855 len = QT_UINT32 (stsd_entry_data);
9856 if (len > remaining_stsd_len)
9859 entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
9860 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
9861 GST_FOURCC_ARGS (entry->fourcc));
9862 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
9864 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
9865 goto error_encrypted;
9867 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
9868 /* FIXME this looks wrong, there might be multiple children
9869 * with the same type */
9870 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
9871 stream->protected = TRUE;
9872 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
9873 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
9876 if (stream->subtype == FOURCC_vide) {
9878 gint depth, palette_size, palette_count;
9879 guint32 *palette_data = NULL;
9881 entry->sampled = TRUE;
9883 stream->display_width = w >> 16;
9884 stream->display_height = h >> 16;
9887 if (len < 86) /* TODO verify */
9890 entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
9891 entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
9892 entry->fps_n = 0; /* this is filled in later */
9893 entry->fps_d = 0; /* this is filled in later */
9894 entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
9895 entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
9897 /* if color_table_id is 0, ctab atom must follow; however some files
9898 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
9899 * if color table is not present we'll correct the value */
9900 if (entry->color_table_id == 0 &&
9902 || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
9903 entry->color_table_id = -1;
9906 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
9907 entry->width, entry->height, entry->bits_per_sample,
9908 entry->color_table_id);
9910 depth = entry->bits_per_sample;
9912 /* more than 32 bits means grayscale */
9913 gray = (depth > 32);
9914 /* low 32 bits specify the depth */
9917 /* different number of palette entries is determined by depth. */
9919 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
9920 palette_count = (1 << depth);
9921 palette_size = palette_count * 4;
9923 if (entry->color_table_id) {
9924 switch (palette_count) {
9928 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
9931 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
9936 g_memdup (ff_qt_grayscale_palette_16, palette_size);
9938 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
9943 g_memdup (ff_qt_grayscale_palette_256, palette_size);
9945 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
9948 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
9949 (_("The video in this file might not play correctly.")),
9950 ("unsupported palette depth %d", depth));
9954 gint i, j, start, end;
9960 start = QT_UINT32 (stsd_entry_data + offset + 70);
9961 palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
9962 end = QT_UINT16 (stsd_entry_data + offset + 76);
9964 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
9965 start, end, palette_count);
9972 if (len < 94 + (end - start) * 8)
9975 /* palette is always the same size */
9976 palette_data = g_malloc0 (256 * 4);
9977 palette_size = 256 * 4;
9979 for (j = 0, i = start; i <= end; j++, i++) {
9982 a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
9983 r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
9984 g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
9985 b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
9987 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
9988 (g & 0xff00) | (b >> 8);
9993 gst_caps_unref (entry->caps);
9996 qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
9998 if (G_UNLIKELY (!entry->caps)) {
9999 g_free (palette_data);
10000 goto unknown_stream;
10004 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
10005 GST_TAG_VIDEO_CODEC, codec, NULL);
10010 if (palette_data) {
10013 if (entry->rgb8_palette)
10014 gst_memory_unref (entry->rgb8_palette);
10015 entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
10016 palette_data, palette_size, 0, palette_size, palette_data, g_free);
10018 s = gst_caps_get_structure (entry->caps, 0);
10020 /* non-raw video has a palette_data property. raw video has the palette as
10021 * an extra plane that we append to the output buffers before we push
10023 if (!gst_structure_has_name (s, "video/x-raw")) {
10024 GstBuffer *palette;
10026 palette = gst_buffer_new ();
10027 gst_buffer_append_memory (palette, entry->rgb8_palette);
10028 entry->rgb8_palette = NULL;
10030 gst_caps_set_simple (entry->caps, "palette_data",
10031 GST_TYPE_BUFFER, palette, NULL);
10032 gst_buffer_unref (palette);
10034 } else if (palette_count != 0) {
10035 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
10036 (NULL), ("Unsupported palette depth %d", depth));
10039 GST_LOG_OBJECT (qtdemux, "frame count: %u",
10040 QT_UINT16 (stsd_entry_data + offset + 32));
10046 /* pick 'the' stsd child */
10047 mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10048 if (!stream->protected) {
10049 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
10053 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) {
10059 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
10060 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
10061 colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
10062 fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
10066 const guint8 *pasp_data = (const guint8 *) pasp->data;
10067 gint len = QT_UINT32 (pasp_data);
10070 CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
10071 CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
10073 CUR_STREAM (stream)->par_w = 0;
10074 CUR_STREAM (stream)->par_h = 0;
10077 CUR_STREAM (stream)->par_w = 0;
10078 CUR_STREAM (stream)->par_h = 0;
10082 const guint8 *fiel_data = (const guint8 *) fiel->data;
10083 gint len = QT_UINT32 (fiel_data);
10086 CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
10087 CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
10092 const guint8 *colr_data = (const guint8 *) colr->data;
10093 gint len = QT_UINT32 (colr_data);
10095 if (len == 19 || len == 18) {
10096 guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
10098 if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
10099 guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
10100 guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
10101 guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
10102 gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
10104 switch (primaries) {
10106 CUR_STREAM (stream)->colorimetry.primaries =
10107 GST_VIDEO_COLOR_PRIMARIES_BT709;
10110 CUR_STREAM (stream)->colorimetry.primaries =
10111 GST_VIDEO_COLOR_PRIMARIES_BT470BG;
10114 CUR_STREAM (stream)->colorimetry.primaries =
10115 GST_VIDEO_COLOR_PRIMARIES_SMPTE170M;
10118 CUR_STREAM (stream)->colorimetry.primaries =
10119 GST_VIDEO_COLOR_PRIMARIES_BT2020;
10125 switch (transfer_function) {
10127 CUR_STREAM (stream)->colorimetry.transfer =
10128 GST_VIDEO_TRANSFER_BT709;
10131 CUR_STREAM (stream)->colorimetry.transfer =
10132 GST_VIDEO_TRANSFER_SMPTE240M;
10140 CUR_STREAM (stream)->colorimetry.matrix =
10141 GST_VIDEO_COLOR_MATRIX_BT709;
10144 CUR_STREAM (stream)->colorimetry.matrix =
10145 GST_VIDEO_COLOR_MATRIX_BT601;
10148 CUR_STREAM (stream)->colorimetry.matrix =
10149 GST_VIDEO_COLOR_MATRIX_SMPTE240M;
10152 CUR_STREAM (stream)->colorimetry.matrix =
10153 GST_VIDEO_COLOR_MATRIX_BT2020;
10159 CUR_STREAM (stream)->colorimetry.range =
10160 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
10161 GST_VIDEO_COLOR_RANGE_16_235;
10163 GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
10166 GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
10171 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
10172 stream->stream_tags);
10179 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10180 const guint8 *avc_data = stsd_entry_data + 0x56;
10183 while (len >= 0x8) {
10186 if (QT_UINT32 (avc_data) <= len)
10187 size = QT_UINT32 (avc_data) - 0x8;
10192 /* No real data, so break out */
10195 switch (QT_FOURCC (avc_data + 0x4)) {
10198 /* parse, if found */
10201 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
10203 /* First 4 bytes are the length of the atom, the next 4 bytes
10204 * are the fourcc, the next 1 byte is the version, and the
10205 * subsequent bytes are profile_tier_level structure like data. */
10206 gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
10207 avc_data + 8 + 1, size - 1);
10208 buf = gst_buffer_new_and_alloc (size);
10209 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
10210 gst_caps_set_simple (entry->caps,
10211 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10212 gst_buffer_unref (buf);
10220 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
10222 /* First 4 bytes are the length of the atom, the next 4 bytes
10223 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
10224 * next 1 byte is the version, and the
10225 * subsequent bytes are sequence parameter set like data. */
10227 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
10229 gst_codec_utils_h264_caps_set_level_and_profile
10230 (entry->caps, avc_data + 8 + 40 + 1, size - 1);
10232 buf = gst_buffer_new_and_alloc (size);
10233 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
10234 gst_caps_set_simple (entry->caps,
10235 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10236 gst_buffer_unref (buf);
10242 guint avg_bitrate, max_bitrate;
10244 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
10248 max_bitrate = QT_UINT32 (avc_data + 0xc);
10249 avg_bitrate = QT_UINT32 (avc_data + 0x10);
10251 if (!max_bitrate && !avg_bitrate)
10254 /* Some muxers seem to swap the average and maximum bitrates
10255 * (I'm looking at you, YouTube), so we swap for sanity. */
10256 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
10257 guint temp = avg_bitrate;
10259 avg_bitrate = max_bitrate;
10260 max_bitrate = temp;
10263 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
10264 gst_tag_list_add (stream->stream_tags,
10265 GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
10266 max_bitrate, NULL);
10268 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
10269 gst_tag_list_add (stream->stream_tags,
10270 GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
10282 avc_data += size + 8;
10291 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10292 const guint8 *hevc_data = stsd_entry_data + 0x56;
10295 while (len >= 0x8) {
10298 if (QT_UINT32 (hevc_data) <= len)
10299 size = QT_UINT32 (hevc_data) - 0x8;
10304 /* No real data, so break out */
10307 switch (QT_FOURCC (hevc_data + 0x4)) {
10310 /* parse, if found */
10313 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
10315 /* First 4 bytes are the length of the atom, the next 4 bytes
10316 * are the fourcc, the next 1 byte is the version, and the
10317 * subsequent bytes are sequence parameter set like data. */
10318 gst_codec_utils_h265_caps_set_level_tier_and_profile
10319 (entry->caps, hevc_data + 8 + 1, size - 1);
10321 buf = gst_buffer_new_and_alloc (size);
10322 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
10323 gst_caps_set_simple (entry->caps,
10324 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10325 gst_buffer_unref (buf);
10332 hevc_data += size + 8;
10345 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
10346 GST_FOURCC_ARGS (fourcc));
10348 /* codec data might be in glbl extension atom */
10350 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
10356 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
10358 len = QT_UINT32 (data);
10361 buf = gst_buffer_new_and_alloc (len);
10362 gst_buffer_fill (buf, 0, data + 8, len);
10363 gst_caps_set_simple (entry->caps,
10364 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10365 gst_buffer_unref (buf);
10372 /* see annex I of the jpeg2000 spec */
10373 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
10374 const guint8 *data;
10375 const gchar *colorspace = NULL;
10377 guint32 ncomp_map = 0;
10378 gint32 *comp_map = NULL;
10379 guint32 nchan_def = 0;
10380 gint32 *chan_def = NULL;
10382 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
10383 /* some required atoms */
10384 mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10387 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
10391 /* number of components; redundant with info in codestream, but useful
10393 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
10394 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
10396 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
10398 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
10401 GST_DEBUG_OBJECT (qtdemux, "found colr");
10402 /* extract colour space info */
10403 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
10404 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
10406 colorspace = "sRGB";
10409 colorspace = "GRAY";
10412 colorspace = "sYUV";
10420 /* colr is required, and only values 16, 17, and 18 are specified,
10421 so error if we have no colorspace */
10424 /* extract component mapping */
10425 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
10427 guint32 cmap_len = 0;
10429 cmap_len = QT_UINT32 (cmap->data);
10430 if (cmap_len >= 8) {
10431 /* normal box, subtract off header */
10433 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
10434 if (cmap_len % 4 == 0) {
10435 ncomp_map = (cmap_len / 4);
10436 comp_map = g_new0 (gint32, ncomp_map);
10437 for (i = 0; i < ncomp_map; i++) {
10440 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
10441 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
10442 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
10443 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
10448 /* extract channel definitions */
10449 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
10451 guint32 cdef_len = 0;
10453 cdef_len = QT_UINT32 (cdef->data);
10454 if (cdef_len >= 10) {
10455 /* normal box, subtract off header and len */
10457 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
10458 if (cdef_len % 6 == 0) {
10459 nchan_def = (cdef_len / 6);
10460 chan_def = g_new0 (gint32, nchan_def);
10461 for (i = 0; i < nchan_def; i++)
10463 for (i = 0; i < nchan_def; i++) {
10464 guint16 cn, typ, asoc;
10465 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
10466 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
10467 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
10468 if (cn < nchan_def) {
10471 chan_def[cn] = asoc;
10474 chan_def[cn] = 0; /* alpha */
10477 chan_def[cn] = -typ;
10485 gst_caps_set_simple (entry->caps,
10486 "num-components", G_TYPE_INT, ncomp, NULL);
10487 gst_caps_set_simple (entry->caps,
10488 "colorspace", G_TYPE_STRING, colorspace, NULL);
10491 GValue arr = { 0, };
10492 GValue elt = { 0, };
10494 g_value_init (&arr, GST_TYPE_ARRAY);
10495 g_value_init (&elt, G_TYPE_INT);
10496 for (i = 0; i < ncomp_map; i++) {
10497 g_value_set_int (&elt, comp_map[i]);
10498 gst_value_array_append_value (&arr, &elt);
10500 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
10501 "component-map", &arr);
10502 g_value_unset (&elt);
10503 g_value_unset (&arr);
10508 GValue arr = { 0, };
10509 GValue elt = { 0, };
10511 g_value_init (&arr, GST_TYPE_ARRAY);
10512 g_value_init (&elt, G_TYPE_INT);
10513 for (i = 0; i < nchan_def; i++) {
10514 g_value_set_int (&elt, chan_def[i]);
10515 gst_value_array_append_value (&arr, &elt);
10517 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
10518 "channel-definitions", &arr);
10519 g_value_unset (&elt);
10520 g_value_unset (&arr);
10524 /* some optional atoms */
10525 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
10526 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
10528 /* indicate possible fields in caps */
10530 data = (guint8 *) field->data + 8;
10532 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
10533 (gint) * data, NULL);
10535 /* add codec_data if provided */
10540 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
10541 data = prefix->data;
10542 len = QT_UINT32 (data);
10545 buf = gst_buffer_new_and_alloc (len);
10546 gst_buffer_fill (buf, 0, data + 8, len);
10547 gst_caps_set_simple (entry->caps,
10548 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10549 gst_buffer_unref (buf);
10558 GstBuffer *seqh = NULL;
10559 const guint8 *gamma_data = NULL;
10560 gint len = QT_UINT32 (stsd_data); /* FIXME review - why put the whole stsd in codec data? */
10562 qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
10565 gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
10566 QT_FP32 (gamma_data), NULL);
10569 /* sorry for the bad name, but we don't know what this is, other
10570 * than its own fourcc */
10571 gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
10573 gst_buffer_unref (seqh);
10576 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
10577 buf = gst_buffer_new_and_alloc (len);
10578 gst_buffer_fill (buf, 0, stsd_data, len);
10579 gst_caps_set_simple (entry->caps,
10580 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10581 gst_buffer_unref (buf);
10586 /* https://developer.apple.com/standards/qtff-2001.pdf,
10587 * page 92, "Video Sample Description", under table 3.1 */
10590 const gint compressor_offset =
10591 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
10592 const gint min_size = compressor_offset + 32 + 2 + 2;
10595 guint16 color_table_id = 0;
10598 GST_DEBUG_OBJECT (qtdemux, "found jpeg");
10600 /* recover information on interlaced/progressive */
10601 jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
10605 len = QT_UINT32 (jpeg->data);
10606 GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
10608 if (len >= min_size) {
10609 gst_byte_reader_init (&br, jpeg->data, len);
10611 gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
10612 gst_byte_reader_get_uint16_le (&br, &color_table_id);
10613 if (color_table_id != 0) {
10614 /* the spec says there can be concatenated chunks in the data, and we want
10615 * to find one called field. Walk through them. */
10616 gint offset = min_size;
10617 while (offset + 8 < len) {
10618 guint32 size = 0, tag;
10619 ok = gst_byte_reader_get_uint32_le (&br, &size);
10620 ok &= gst_byte_reader_get_uint32_le (&br, &tag);
10621 if (!ok || size < 8) {
10622 GST_WARNING_OBJECT (qtdemux,
10623 "Failed to walk optional chunk list");
10626 GST_DEBUG_OBJECT (qtdemux,
10627 "Found optional %4.4s chunk, size %u",
10628 (const char *) &tag, size);
10629 if (tag == FOURCC_fiel) {
10630 guint8 n_fields = 0, ordering = 0;
10631 gst_byte_reader_get_uint8 (&br, &n_fields);
10632 gst_byte_reader_get_uint8 (&br, &ordering);
10633 if (n_fields == 1 || n_fields == 2) {
10634 GST_DEBUG_OBJECT (qtdemux,
10635 "Found fiel tag with %u fields, ordering %u",
10636 n_fields, ordering);
10638 gst_caps_set_simple (CUR_STREAM (stream)->caps,
10639 "interlace-mode", G_TYPE_STRING, "interleaved",
10642 GST_WARNING_OBJECT (qtdemux,
10643 "Found fiel tag with invalid fields (%u)", n_fields);
10649 GST_DEBUG_OBJECT (qtdemux,
10650 "Color table ID is 0, not trying to get interlacedness");
10653 GST_WARNING_OBJECT (qtdemux,
10654 "Length of jpeg chunk is too small, not trying to get interlacedness");
10662 gst_caps_set_simple (entry->caps,
10663 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 66),
10669 GNode *xith, *xdxt;
10671 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
10672 xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10676 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
10680 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
10681 /* collect the headers and store them in a stream list so that we can
10682 * send them out first */
10683 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
10693 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
10694 ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10697 ovc1_data = ovc1->data;
10698 ovc1_len = QT_UINT32 (ovc1_data);
10699 if (ovc1_len <= 198) {
10700 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
10703 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
10704 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
10705 gst_caps_set_simple (entry->caps,
10706 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10707 gst_buffer_unref (buf);
10712 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10713 const guint8 *vc1_data = stsd_entry_data + 0x56;
10719 if (QT_UINT32 (vc1_data) <= len)
10720 size = QT_UINT32 (vc1_data) - 8;
10725 /* No real data, so break out */
10728 switch (QT_FOURCC (vc1_data + 0x4)) {
10729 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
10733 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
10734 buf = gst_buffer_new_and_alloc (size);
10735 gst_buffer_fill (buf, 0, vc1_data + 8, size);
10736 gst_caps_set_simple (entry->caps,
10737 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10738 gst_buffer_unref (buf);
10745 vc1_data += size + 8;
10754 GST_INFO_OBJECT (qtdemux,
10755 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10756 GST_FOURCC_ARGS (fourcc), entry->caps);
10758 } else if (stream->subtype == FOURCC_soun) {
10759 int version, samplesize;
10760 guint16 compression_id;
10761 gboolean amrwb = FALSE;
10764 /* sample description entry (16) + sound sample description v0 (20) */
10768 version = QT_UINT32 (stsd_entry_data + offset);
10769 entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
10770 samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
10771 compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
10772 entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
10774 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
10775 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
10776 QT_UINT32 (stsd_entry_data + offset + 4));
10777 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
10778 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
10779 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
10780 GST_LOG_OBJECT (qtdemux, "packet size: %d",
10781 QT_UINT16 (stsd_entry_data + offset + 14));
10782 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
10784 if (compression_id == 0xfffe)
10785 entry->sampled = TRUE;
10787 /* first assume uncompressed audio */
10788 entry->bytes_per_sample = samplesize / 8;
10789 entry->samples_per_frame = entry->n_channels;
10790 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
10791 entry->samples_per_packet = entry->samples_per_frame;
10792 entry->bytes_per_packet = entry->bytes_per_sample;
10796 /* Yes, these have to be hard-coded */
10799 entry->samples_per_packet = 6;
10800 entry->bytes_per_packet = 1;
10801 entry->bytes_per_frame = 1 * entry->n_channels;
10802 entry->bytes_per_sample = 1;
10803 entry->samples_per_frame = 6 * entry->n_channels;
10808 entry->samples_per_packet = 3;
10809 entry->bytes_per_packet = 1;
10810 entry->bytes_per_frame = 1 * entry->n_channels;
10811 entry->bytes_per_sample = 1;
10812 entry->samples_per_frame = 3 * entry->n_channels;
10817 entry->samples_per_packet = 64;
10818 entry->bytes_per_packet = 34;
10819 entry->bytes_per_frame = 34 * entry->n_channels;
10820 entry->bytes_per_sample = 2;
10821 entry->samples_per_frame = 64 * entry->n_channels;
10827 entry->samples_per_packet = 1;
10828 entry->bytes_per_packet = 1;
10829 entry->bytes_per_frame = 1 * entry->n_channels;
10830 entry->bytes_per_sample = 1;
10831 entry->samples_per_frame = 1 * entry->n_channels;
10836 entry->samples_per_packet = 160;
10837 entry->bytes_per_packet = 33;
10838 entry->bytes_per_frame = 33 * entry->n_channels;
10839 entry->bytes_per_sample = 2;
10840 entry->samples_per_frame = 160 * entry->n_channels;
10847 if (version == 0x00010000) {
10848 /* sample description entry (16) + sound sample description v1 (20+16) */
10860 /* only parse extra decoding config for non-pcm audio */
10861 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
10862 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
10863 entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
10864 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
10866 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
10867 entry->samples_per_packet);
10868 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
10869 entry->bytes_per_packet);
10870 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
10871 entry->bytes_per_frame);
10872 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
10873 entry->bytes_per_sample);
10875 if (!entry->sampled && entry->bytes_per_packet) {
10876 entry->samples_per_frame = (entry->bytes_per_frame /
10877 entry->bytes_per_packet) * entry->samples_per_packet;
10878 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
10879 entry->samples_per_frame);
10884 } else if (version == 0x00020000) {
10891 /* sample description entry (16) + sound sample description v2 (56) */
10895 qtfp.val = QT_UINT64 (stsd_entry_data + offset + 4);
10896 entry->rate = qtfp.fp;
10897 entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
10899 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
10900 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
10901 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
10902 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
10903 QT_UINT32 (stsd_entry_data + offset + 20));
10904 GST_LOG_OBJECT (qtdemux, "format flags: %X",
10905 QT_UINT32 (stsd_entry_data + offset + 24));
10906 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
10907 QT_UINT32 (stsd_entry_data + offset + 28));
10908 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
10909 QT_UINT32 (stsd_entry_data + offset + 32));
10910 } else if (version != 0x00000) {
10911 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
10916 gst_caps_unref (entry->caps);
10918 entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
10919 stsd_entry_data + 32, len - 16, &codec);
10927 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
10929 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
10931 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
10933 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
10936 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
10937 gst_caps_set_simple (entry->caps,
10938 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE",
10945 const guint8 *owma_data;
10946 const gchar *codec_name = NULL;
10950 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
10951 /* FIXME this should also be gst_riff_strf_auds,
10952 * but the latter one is actually missing bits-per-sample :( */
10957 gint32 nSamplesPerSec;
10958 gint32 nAvgBytesPerSec;
10959 gint16 nBlockAlign;
10960 gint16 wBitsPerSample;
10963 WAVEFORMATEX *wfex;
10965 GST_DEBUG_OBJECT (qtdemux, "parse owma");
10966 owma_data = stsd_entry_data;
10967 owma_len = QT_UINT32 (owma_data);
10968 if (owma_len <= 54) {
10969 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
10972 wfex = (WAVEFORMATEX *) (owma_data + 36);
10973 buf = gst_buffer_new_and_alloc (owma_len - 54);
10974 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
10975 if (wfex->wFormatTag == 0x0161) {
10976 codec_name = "Windows Media Audio";
10978 } else if (wfex->wFormatTag == 0x0162) {
10979 codec_name = "Windows Media Audio 9 Pro";
10981 } else if (wfex->wFormatTag == 0x0163) {
10982 codec_name = "Windows Media Audio 9 Lossless";
10983 /* is that correct? gstffmpegcodecmap.c is missing it, but
10984 * fluendo codec seems to support it */
10988 gst_caps_set_simple (entry->caps,
10989 "codec_data", GST_TYPE_BUFFER, buf,
10990 "wmaversion", G_TYPE_INT, version,
10991 "block_align", G_TYPE_INT,
10992 GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
10993 GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
10994 GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
10995 GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
10996 gst_buffer_unref (buf);
11000 codec = g_strdup (codec_name);
11006 gint len = QT_UINT32 (stsd_entry_data) - offset;
11007 const guint8 *wfex_data = stsd_entry_data + offset;
11008 const gchar *codec_name = NULL;
11010 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
11011 /* FIXME this should also be gst_riff_strf_auds,
11012 * but the latter one is actually missing bits-per-sample :( */
11017 gint32 nSamplesPerSec;
11018 gint32 nAvgBytesPerSec;
11019 gint16 nBlockAlign;
11020 gint16 wBitsPerSample;
11025 /* FIXME: unify with similar wavformatex parsing code above */
11026 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
11032 if (QT_UINT32 (wfex_data) <= len)
11033 size = QT_UINT32 (wfex_data) - 8;
11038 /* No real data, so break out */
11041 switch (QT_FOURCC (wfex_data + 4)) {
11042 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
11044 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
11049 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
11050 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
11051 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
11052 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
11053 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
11054 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
11055 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
11057 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
11058 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
11059 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
11060 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
11061 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
11062 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
11064 if (wfex.wFormatTag == 0x0161) {
11065 codec_name = "Windows Media Audio";
11067 } else if (wfex.wFormatTag == 0x0162) {
11068 codec_name = "Windows Media Audio 9 Pro";
11070 } else if (wfex.wFormatTag == 0x0163) {
11071 codec_name = "Windows Media Audio 9 Lossless";
11072 /* is that correct? gstffmpegcodecmap.c is missing it, but
11073 * fluendo codec seems to support it */
11077 gst_caps_set_simple (entry->caps,
11078 "wmaversion", G_TYPE_INT, version,
11079 "block_align", G_TYPE_INT, wfex.nBlockAlign,
11080 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
11081 "width", G_TYPE_INT, wfex.wBitsPerSample,
11082 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
11084 if (size > wfex.cbSize) {
11087 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
11088 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
11089 size - wfex.cbSize);
11090 gst_caps_set_simple (entry->caps,
11091 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11092 gst_buffer_unref (buf);
11094 GST_WARNING_OBJECT (qtdemux, "no codec data");
11099 codec = g_strdup (codec_name);
11107 wfex_data += size + 8;
11113 const guint8 *opus_data;
11114 guint8 *channel_mapping = NULL;
11117 guint8 channel_mapping_family;
11118 guint8 stream_count;
11119 guint8 coupled_count;
11122 opus_data = stsd_entry_data;
11124 channels = GST_READ_UINT8 (opus_data + 45);
11125 rate = GST_READ_UINT32_LE (opus_data + 48);
11126 channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
11127 stream_count = GST_READ_UINT8 (opus_data + 55);
11128 coupled_count = GST_READ_UINT8 (opus_data + 56);
11130 if (channels > 0) {
11131 channel_mapping = g_malloc (channels * sizeof (guint8));
11132 for (i = 0; i < channels; i++)
11133 channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
11136 entry->caps = gst_codec_utils_opus_create_caps (rate, channels,
11137 channel_mapping_family, stream_count, coupled_count,
11149 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11150 GST_TAG_AUDIO_CODEC, codec, NULL);
11154 /* some bitrate info may have ended up in caps */
11155 s = gst_caps_get_structure (entry->caps, 0);
11156 gst_structure_get_int (s, "bitrate", &bitrate);
11158 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11159 GST_TAG_BITRATE, bitrate, NULL);
11162 mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11163 if (!stream->protected) {
11165 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) {
11169 if (stream->protected && fourcc == FOURCC_mp4a) {
11170 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) {
11174 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_mp4a) {
11182 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
11184 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
11186 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
11190 /* If the fourcc's bottom 16 bits gives 'sm', then the top
11191 16 bits is a byte-swapped wave-style codec identifier,
11192 and we can find a WAVE header internally to a 'wave' atom here.
11193 This can more clearly be thought of as 'ms' as the top 16 bits, and a
11194 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
11197 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
11198 if (len < offset + 20) {
11199 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
11201 guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
11202 const guint8 *data = stsd_entry_data + offset + 16;
11204 GNode *waveheadernode;
11206 wavenode = g_node_new ((guint8 *) data);
11207 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
11208 const guint8 *waveheader;
11211 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
11212 if (waveheadernode) {
11213 waveheader = (const guint8 *) waveheadernode->data;
11214 headerlen = QT_UINT32 (waveheader);
11216 if (headerlen > 8) {
11217 gst_riff_strf_auds *header = NULL;
11218 GstBuffer *headerbuf;
11224 headerbuf = gst_buffer_new_and_alloc (headerlen);
11225 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
11227 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
11228 headerbuf, &header, &extra)) {
11229 gst_caps_unref (entry->caps);
11230 /* FIXME: Need to do something with the channel reorder map */
11232 gst_riff_create_audio_caps (header->format, NULL, header,
11233 extra, NULL, NULL, NULL);
11236 gst_buffer_unref (extra);
11241 GST_DEBUG ("Didn't find waveheadernode for this codec");
11243 g_node_destroy (wavenode);
11246 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11247 stream->stream_tags);
11251 /* FIXME: what is in the chunk? */
11254 gint len = QT_UINT32 (stsd_data);
11256 /* seems to be always = 116 = 0x74 */
11262 gint len = QT_UINT32 (stsd_entry_data);
11265 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
11267 gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
11268 gst_caps_set_simple (entry->caps,
11269 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11270 gst_buffer_unref (buf);
11272 gst_caps_set_simple (entry->caps,
11273 "samplesize", G_TYPE_INT, samplesize, NULL);
11278 GNode *alac, *wave = NULL;
11280 /* apparently, m4a has this atom appended directly in the stsd entry,
11281 * while mov has it in a wave atom */
11282 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
11284 /* alac now refers to stsd entry atom */
11285 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
11287 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
11289 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
11292 const guint8 *alac_data = alac->data;
11293 gint len = QT_UINT32 (alac->data);
11297 GST_DEBUG_OBJECT (qtdemux,
11298 "discarding alac atom with unexpected len %d", len);
11300 /* codec-data contains alac atom size and prefix,
11301 * ffmpeg likes it that way, not quite gst-ish though ...*/
11302 buf = gst_buffer_new_and_alloc (len);
11303 gst_buffer_fill (buf, 0, alac->data, len);
11304 gst_caps_set_simple (entry->caps,
11305 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11306 gst_buffer_unref (buf);
11308 entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
11309 entry->n_channels = QT_UINT8 (alac_data + 21);
11310 entry->rate = QT_UINT32 (alac_data + 32);
11313 gst_caps_set_simple (entry->caps,
11314 "samplesize", G_TYPE_INT, samplesize, NULL);
11319 /* The codingname of the sample entry is 'fLaC' */
11320 GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
11323 /* The 'dfLa' box is added to the sample entry to convey
11324 initializing information for the decoder. */
11325 const GNode *dfla =
11326 qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
11329 const guint32 len = QT_UINT32 (dfla->data);
11331 /* Must contain at least dfLa box header (12),
11332 * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
11334 GST_DEBUG_OBJECT (qtdemux,
11335 "discarding dfla atom with unexpected len %d", len);
11337 /* skip dfLa header to get the METADATA_BLOCKs */
11338 const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
11339 const guint32 metadata_blocks_len = len - 12;
11341 gchar *stream_marker = g_strdup ("fLaC");
11342 GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
11343 strlen (stream_marker));
11346 guint32 remainder = 0;
11347 guint32 block_size = 0;
11348 gboolean is_last = FALSE;
11350 GValue array = G_VALUE_INIT;
11351 GValue value = G_VALUE_INIT;
11353 g_value_init (&array, GST_TYPE_ARRAY);
11354 g_value_init (&value, GST_TYPE_BUFFER);
11356 gst_value_set_buffer (&value, block);
11357 gst_value_array_append_value (&array, &value);
11358 g_value_reset (&value);
11360 gst_buffer_unref (block);
11362 /* check there's at least one METADATA_BLOCK_HEADER's worth
11363 * of data, and we haven't already finished parsing */
11364 while (!is_last && ((index + 3) < metadata_blocks_len)) {
11365 remainder = metadata_blocks_len - index;
11367 /* add the METADATA_BLOCK_HEADER size to the signalled size */
11369 (metadata_blocks[index + 1] << 16) +
11370 (metadata_blocks[index + 2] << 8) +
11371 metadata_blocks[index + 3];
11373 /* be careful not to read off end of box */
11374 if (block_size > remainder) {
11378 is_last = metadata_blocks[index] >> 7;
11380 block = gst_buffer_new_and_alloc (block_size);
11382 gst_buffer_fill (block, 0, &metadata_blocks[index],
11385 gst_value_set_buffer (&value, block);
11386 gst_value_array_append_value (&array, &value);
11387 g_value_reset (&value);
11389 gst_buffer_unref (block);
11391 index += block_size;
11394 /* only append the metadata if we successfully read all of it */
11396 gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
11397 (stream)->caps, 0), "streamheader", &array);
11399 GST_WARNING_OBJECT (qtdemux,
11400 "discarding all METADATA_BLOCKs due to invalid "
11401 "block_size %d at idx %d, rem %d", block_size, index,
11405 g_value_unset (&value);
11406 g_value_unset (&array);
11408 /* The sample rate obtained from the stsd may not be accurate
11409 * since it cannot represent rates greater than 65535Hz, so
11410 * override that value with the sample rate from the
11411 * METADATA_BLOCK_STREAMINFO block */
11412 CUR_STREAM (stream)->rate =
11413 (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
11424 gint len = QT_UINT32 (stsd_entry_data);
11427 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
11430 gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
11432 /* If we have enough data, let's try to get the 'damr' atom. See
11433 * the 3GPP container spec (26.244) for more details. */
11434 if ((len - 0x34) > 8 &&
11435 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
11436 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11437 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
11440 gst_caps_set_simple (entry->caps,
11441 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11442 gst_buffer_unref (buf);
11448 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
11449 gint len = QT_UINT32 (stsd_entry_data);
11452 guint16 sound_version = QT_UINT16 (stsd_entry_data + 16);
11454 if (sound_version == 1) {
11455 guint16 channels = QT_UINT16 (stsd_entry_data + 24);
11456 guint32 time_scale = QT_UINT32 (stsd_entry_data + 30);
11457 guint8 codec_data[2];
11459 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
11461 gint sample_rate_index =
11462 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
11464 /* build AAC codec data */
11465 codec_data[0] = profile << 3;
11466 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
11467 codec_data[1] = (sample_rate_index & 0x01) << 7;
11468 codec_data[1] |= (channels & 0xF) << 3;
11470 buf = gst_buffer_new_and_alloc (2);
11471 gst_buffer_fill (buf, 0, codec_data, 2);
11472 gst_caps_set_simple (entry->caps,
11473 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11474 gst_buffer_unref (buf);
11480 /* Fully handled elsewhere */
11483 GST_INFO_OBJECT (qtdemux,
11484 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11488 GST_INFO_OBJECT (qtdemux,
11489 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11490 GST_FOURCC_ARGS (fourcc), entry->caps);
11492 } else if (stream->subtype == FOURCC_strm) {
11493 if (fourcc == FOURCC_rtsp) {
11494 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
11496 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
11497 GST_FOURCC_ARGS (fourcc));
11498 goto unknown_stream;
11500 entry->sampled = TRUE;
11501 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
11502 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
11504 entry->sampled = TRUE;
11505 entry->sparse = TRUE;
11508 qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11511 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11512 GST_TAG_SUBTITLE_CODEC, codec, NULL);
11517 /* hunt for sort-of codec data */
11521 GNode *mp4s = NULL;
11522 GNode *esds = NULL;
11524 /* look for palette in a stsd->mp4s->esds sub-atom */
11525 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
11527 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
11528 if (esds == NULL) {
11530 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
11534 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11535 stream->stream_tags);
11539 GST_INFO_OBJECT (qtdemux,
11540 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11543 GST_INFO_OBJECT (qtdemux,
11544 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11545 GST_FOURCC_ARGS (fourcc), entry->caps);
11547 /* everything in 1 sample */
11548 entry->sampled = TRUE;
11551 qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11554 if (entry->caps == NULL)
11555 goto unknown_stream;
11558 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11559 GST_TAG_SUBTITLE_CODEC, codec, NULL);
11565 /* promote to sampled format */
11566 if (entry->fourcc == FOURCC_samr) {
11567 /* force mono 8000 Hz for AMR */
11568 entry->sampled = TRUE;
11569 entry->n_channels = 1;
11570 entry->rate = 8000;
11571 } else if (entry->fourcc == FOURCC_sawb) {
11572 /* force mono 16000 Hz for AMR-WB */
11573 entry->sampled = TRUE;
11574 entry->n_channels = 1;
11575 entry->rate = 16000;
11576 } else if (entry->fourcc == FOURCC_mp4a) {
11577 entry->sampled = TRUE;
11581 stsd_entry_data += len;
11582 remaining_stsd_len -= len;
11586 /* collect sample information */
11587 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
11588 goto samples_failed;
11590 if (qtdemux->fragmented) {
11593 /* need all moov samples as basis; probably not many if any at all */
11594 /* prevent moof parsing taking of at this time */
11595 offset = qtdemux->moof_offset;
11596 qtdemux->moof_offset = 0;
11597 if (stream->n_samples &&
11598 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
11599 qtdemux->moof_offset = offset;
11600 goto samples_failed;
11602 qtdemux->moof_offset = 0;
11603 /* movie duration more reliable in this case (e.g. mehd) */
11604 if (qtdemux->segment.duration &&
11605 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
11607 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
11610 /* configure segments */
11611 if (!qtdemux_parse_segments (qtdemux, stream, trak))
11612 goto segments_failed;
11614 /* add some language tag, if useful */
11615 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
11616 strcmp (stream->lang_id, "und")) {
11617 const gchar *lang_code;
11619 /* convert ISO 639-2 code to ISO 639-1 */
11620 lang_code = gst_tag_get_language_code (stream->lang_id);
11621 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11622 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
11625 /* Check for UDTA tags */
11626 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
11627 qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
11630 /* now we are ready to add the stream */
11631 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
11632 goto too_many_streams;
11634 if (!qtdemux->got_moov) {
11635 qtdemux->streams[qtdemux->n_streams] = stream;
11636 qtdemux->n_streams++;
11637 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
11645 GST_INFO_OBJECT (qtdemux, "skip disabled track");
11647 gst_qtdemux_stream_free (qtdemux, stream);
11652 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
11653 (_("This file is corrupt and cannot be played.")), (NULL));
11655 gst_qtdemux_stream_free (qtdemux, stream);
11660 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
11662 gst_qtdemux_stream_free (qtdemux, stream);
11668 /* we posted an error already */
11669 /* free stbl sub-atoms */
11670 gst_qtdemux_stbl_free (stream);
11672 gst_qtdemux_stream_free (qtdemux, stream);
11677 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
11680 gst_qtdemux_stream_free (qtdemux, stream);
11685 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
11686 GST_FOURCC_ARGS (stream->subtype));
11688 gst_qtdemux_stream_free (qtdemux, stream);
11693 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
11694 (_("This file contains too many streams. Only playing first %d"),
11695 GST_QTDEMUX_MAX_STREAMS), (NULL));
11700 /* If we can estimate the overall bitrate, and don't have information about the
11701 * stream bitrate for exactly one stream, this guesses the stream bitrate as
11702 * the overall bitrate minus the sum of the bitrates of all other streams. This
11703 * should be useful for the common case where we have one audio and one video
11704 * stream and can estimate the bitrate of one, but not the other. */
11706 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
11708 QtDemuxStream *stream = NULL;
11709 gint64 size, sys_bitrate, sum_bitrate = 0;
11710 GstClockTime duration;
11714 if (qtdemux->fragmented)
11717 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
11719 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
11721 GST_DEBUG_OBJECT (qtdemux,
11722 "Size in bytes of the stream not known - bailing");
11726 /* Subtract the header size */
11727 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
11728 size, qtdemux->header_size);
11730 if (size < qtdemux->header_size)
11733 size = size - qtdemux->header_size;
11735 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
11736 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
11740 for (i = 0; i < qtdemux->n_streams; i++) {
11741 switch (qtdemux->streams[i]->subtype) {
11744 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
11745 CUR_STREAM (qtdemux->streams[i])->caps);
11746 /* retrieve bitrate, prefer avg then max */
11748 if (qtdemux->streams[i]->stream_tags) {
11749 gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags,
11750 GST_TAG_MAXIMUM_BITRATE, &bitrate);
11751 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
11752 gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags,
11753 GST_TAG_NOMINAL_BITRATE, &bitrate);
11754 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
11755 gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags,
11756 GST_TAG_BITRATE, &bitrate);
11757 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
11760 sum_bitrate += bitrate;
11763 GST_DEBUG_OBJECT (qtdemux,
11764 ">1 stream with unknown bitrate - bailing");
11767 stream = qtdemux->streams[i];
11771 /* For other subtypes, we assume no significant impact on bitrate */
11777 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
11781 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
11783 if (sys_bitrate < sum_bitrate) {
11784 /* This can happen, since sum_bitrate might be derived from maximum
11785 * bitrates and not average bitrates */
11786 GST_DEBUG_OBJECT (qtdemux,
11787 "System bitrate less than sum bitrate - bailing");
11791 bitrate = sys_bitrate - sum_bitrate;
11792 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
11793 ", Stream bitrate = %u", sys_bitrate, bitrate);
11795 if (!stream->stream_tags)
11796 stream->stream_tags = gst_tag_list_new_empty ();
11798 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
11800 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11801 GST_TAG_BITRATE, bitrate, NULL);
11804 static GstFlowReturn
11805 qtdemux_prepare_streams (GstQTDemux * qtdemux)
11808 GstFlowReturn ret = GST_FLOW_OK;
11810 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
11812 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
11813 QtDemuxStream *stream = qtdemux->streams[i];
11814 guint32 sample_num = 0;
11816 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
11817 i, stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
11819 if (qtdemux->fragmented) {
11820 /* need all moov samples first */
11821 GST_OBJECT_LOCK (qtdemux);
11822 while (stream->n_samples == 0)
11823 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
11825 GST_OBJECT_UNLOCK (qtdemux);
11827 /* discard any stray moof */
11828 qtdemux->moof_offset = 0;
11831 /* prepare braking */
11832 if (ret != GST_FLOW_ERROR)
11835 /* in pull mode, we should have parsed some sample info by now;
11836 * and quite some code will not handle no samples.
11837 * in push mode, we'll just have to deal with it */
11838 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
11839 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
11840 gst_qtdemux_remove_stream (qtdemux, i);
11845 /* parse the initial sample for use in setting the frame rate cap */
11846 while (sample_num == 0 && sample_num < stream->n_samples) {
11847 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
11851 if (stream->n_samples > 0 && stream->stbl_index >= 0) {
11852 stream->first_duration = stream->samples[0].duration;
11853 GST_LOG_OBJECT (qtdemux, "stream %d first duration %u",
11854 stream->track_id, stream->first_duration);
11861 static GstFlowReturn
11862 qtdemux_expose_streams (GstQTDemux * qtdemux)
11865 GSList *oldpads = NULL;
11868 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
11870 for (i = 0; i < qtdemux->n_streams; i++) {
11871 QtDemuxStream *stream = qtdemux->streams[i];
11872 GstPad *oldpad = stream->pad;
11875 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
11876 i, stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
11878 if ((stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl) &&
11879 stream->track_id == qtdemux->chapters_track_id) {
11880 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
11881 so that it doesn't look like a subtitle track */
11882 gst_qtdemux_remove_stream (qtdemux, i);
11887 /* now we have all info and can expose */
11888 list = stream->stream_tags;
11889 stream->stream_tags = NULL;
11891 oldpads = g_slist_prepend (oldpads, oldpad);
11892 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
11893 return GST_FLOW_ERROR;
11896 gst_qtdemux_guess_bitrate (qtdemux);
11898 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
11900 for (iter = oldpads; iter; iter = g_slist_next (iter)) {
11901 GstPad *oldpad = iter->data;
11904 event = gst_event_new_eos ();
11905 if (qtdemux->segment_seqnum)
11906 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
11908 gst_pad_push_event (oldpad, event);
11909 gst_pad_set_active (oldpad, FALSE);
11910 gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
11911 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, oldpad);
11912 gst_object_unref (oldpad);
11915 /* check if we should post a redirect in case there is a single trak
11916 * and it is a redirecting trak */
11917 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
11920 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
11921 "an external content");
11922 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
11923 gst_structure_new ("redirect",
11924 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
11926 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
11927 qtdemux->posted_redirect = TRUE;
11930 for (i = 0; i < qtdemux->n_streams; i++) {
11931 QtDemuxStream *stream = qtdemux->streams[i];
11933 qtdemux_do_allocation (qtdemux, stream);
11936 qtdemux->exposed = TRUE;
11937 return GST_FLOW_OK;
11940 /* check if major or compatible brand is 3GP */
11941 static inline gboolean
11942 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
11945 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
11947 } else if (qtdemux->comp_brands != NULL) {
11951 gboolean res = FALSE;
11953 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
11956 while (size >= 4) {
11957 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
11962 gst_buffer_unmap (qtdemux->comp_brands, &map);
11969 /* check if tag is a spec'ed 3GP tag keyword storing a string */
11970 static inline gboolean
11971 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
11973 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
11974 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
11975 || fourcc == FOURCC_albm;
11979 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
11980 const char *tag, const char *dummy, GNode * node)
11982 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11986 gdouble longitude, latitude, altitude;
11989 len = QT_UINT32 (node->data);
11996 /* TODO: language code skipped */
11998 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
12001 /* do not alarm in trivial case, but bail out otherwise */
12002 if (*(data + offset) != 0) {
12003 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
12007 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
12008 GST_TAG_GEO_LOCATION_NAME, name, NULL);
12009 offset += strlen (name);
12013 if (len < offset + 2 + 4 + 4 + 4)
12016 /* +1 +1 = skip null-terminator and location role byte */
12018 /* table in spec says unsigned, semantics say negative has meaning ... */
12019 longitude = QT_SFP32 (data + offset);
12022 latitude = QT_SFP32 (data + offset);
12025 altitude = QT_SFP32 (data + offset);
12027 /* one invalid means all are invalid */
12028 if (longitude >= -180.0 && longitude <= 180.0 &&
12029 latitude >= -90.0 && latitude <= 90.0) {
12030 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
12031 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
12032 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
12033 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
12036 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
12043 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
12050 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
12051 const char *tag, const char *dummy, GNode * node)
12057 len = QT_UINT32 (node->data);
12061 y = QT_UINT16 ((guint8 *) node->data + 12);
12063 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
12066 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
12068 date = g_date_new_dmy (1, 1, y);
12069 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
12070 g_date_free (date);
12074 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
12075 const char *tag, const char *dummy, GNode * node)
12078 char *tag_str = NULL;
12083 len = QT_UINT32 (node->data);
12088 entity = (guint8 *) node->data + offset;
12089 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
12090 GST_DEBUG_OBJECT (qtdemux,
12091 "classification info: %c%c%c%c invalid classification entity",
12092 entity[0], entity[1], entity[2], entity[3]);
12097 table = QT_UINT16 ((guint8 *) node->data + offset);
12099 /* Language code skipped */
12103 /* Tag format: "XXXX://Y[YYYY]/classification info string"
12104 * XXXX: classification entity, fixed length 4 chars.
12105 * Y[YYYY]: classification table, max 5 chars.
12107 tag_str = g_strdup_printf ("----://%u/%s",
12108 table, (char *) node->data + offset);
12110 /* memcpy To be sure we're preserving byte order */
12111 memcpy (tag_str, entity, 4);
12112 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
12114 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
12123 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
12129 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
12130 const char *tag, const char *dummy, GNode * node)
12132 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12138 gboolean ret = TRUE;
12139 const gchar *charset = NULL;
12141 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12143 len = QT_UINT32 (data->data);
12144 type = QT_UINT32 ((guint8 *) data->data + 8);
12145 if (type == 0x00000001 && len > 16) {
12146 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
12149 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
12150 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
12153 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
12157 len = QT_UINT32 (node->data);
12158 type = QT_UINT32 ((guint8 *) node->data + 4);
12159 if ((type >> 24) == 0xa9 && len > 8 + 4) {
12163 /* Type starts with the (C) symbol, so the next data is a list
12164 * of (string size(16), language code(16), string) */
12166 str_len = QT_UINT16 ((guint8 *) node->data + 8);
12167 lang_code = QT_UINT16 ((guint8 *) node->data + 10);
12169 /* the string + fourcc + size + 2 16bit fields,
12170 * means that there are more tags in this atom */
12171 if (len > str_len + 8 + 4) {
12172 /* TODO how to represent the same tag in different languages? */
12173 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
12174 "text alternatives, reading only first one");
12178 len = MIN (len, str_len + 8 + 4); /* remove trailing strings that we don't use */
12179 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
12181 if (lang_code < 0x800) { /* MAC encoded string */
12184 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
12185 QT_FOURCC ((guint8 *) node->data + 4))) {
12186 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
12188 /* we go for 3GP style encoding if major brands claims so,
12189 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
12190 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
12191 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
12192 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
12194 /* 16-bit Language code is ignored here as well */
12195 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
12202 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
12203 ret = FALSE; /* may have to fallback */
12206 GError *err = NULL;
12208 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
12209 charset, NULL, NULL, &err);
12211 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
12212 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
12214 g_error_free (err);
12217 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
12218 len - offset, env_vars);
12221 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
12222 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
12226 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
12233 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
12234 const char *tag, const char *dummy, GNode * node)
12236 qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
12240 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
12241 const char *tag, const char *dummy, GNode * node)
12243 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12245 char *s, *t, *k = NULL;
12250 /* first try normal string tag if major brand not 3GP */
12251 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
12252 if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
12253 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
12254 * let's try it 3gpp way after minor safety check */
12256 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
12262 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
12266 len = QT_UINT32 (data);
12270 count = QT_UINT8 (data + 14);
12272 for (; count; count--) {
12275 if (offset + 1 > len)
12277 slen = QT_UINT8 (data + offset);
12279 if (offset + slen > len)
12281 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
12284 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
12286 t = g_strjoin (",", k, s, NULL);
12294 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
12301 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
12302 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
12311 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
12317 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
12318 const char *tag1, const char *tag2, GNode * node)
12325 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12327 len = QT_UINT32 (data->data);
12328 type = QT_UINT32 ((guint8 *) data->data + 8);
12329 if (type == 0x00000000 && len >= 22) {
12330 n1 = QT_UINT16 ((guint8 *) data->data + 18);
12331 n2 = QT_UINT16 ((guint8 *) data->data + 20);
12333 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
12334 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
12337 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
12338 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
12345 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
12346 const char *tag1, const char *dummy, GNode * node)
12353 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12355 len = QT_UINT32 (data->data);
12356 type = QT_UINT32 ((guint8 *) data->data + 8);
12357 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
12358 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
12359 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
12360 n1 = QT_UINT16 ((guint8 *) data->data + 16);
12362 /* do not add bpm=0 */
12363 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
12364 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
12372 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
12373 const char *tag1, const char *dummy, GNode * node)
12380 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12382 len = QT_UINT32 (data->data);
12383 type = QT_UINT32 ((guint8 *) data->data + 8);
12384 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
12385 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
12386 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
12387 num = QT_UINT32 ((guint8 *) data->data + 16);
12389 /* do not add num=0 */
12390 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
12391 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
12398 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
12399 const char *tag1, const char *dummy, GNode * node)
12406 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12408 len = QT_UINT32 (data->data);
12409 type = QT_UINT32 ((guint8 *) data->data + 8);
12410 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
12411 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
12412 GstTagImageType image_type;
12414 if (gst_tag_list_get_tag_size (taglist, GST_TAG_IMAGE) == 0)
12415 image_type = GST_TAG_IMAGE_TYPE_FRONT_COVER;
12417 image_type = GST_TAG_IMAGE_TYPE_NONE;
12420 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
12421 len - 16, image_type))) {
12422 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
12423 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
12424 gst_sample_unref (sample);
12431 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
12432 const char *tag, const char *dummy, GNode * node)
12439 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12441 len = QT_UINT32 (data->data);
12442 type = QT_UINT32 ((guint8 *) data->data + 8);
12443 if (type == 0x00000001 && len > 16) {
12444 guint y, m = 1, d = 1;
12447 s = g_strndup ((char *) data->data + 16, len - 16);
12448 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
12449 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
12450 if (ret >= 1 && y > 1500 && y < 3000) {
12453 date = g_date_new_dmy (d, m, y);
12454 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
12455 g_date_free (date);
12457 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
12465 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
12466 const char *tag, const char *dummy, GNode * node)
12470 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12472 /* re-route to normal string tag if major brand says so
12473 * or no data atom and compatible brand suggests so */
12474 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
12475 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
12476 qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
12481 guint len, type, n;
12483 len = QT_UINT32 (data->data);
12484 type = QT_UINT32 ((guint8 *) data->data + 8);
12485 if (type == 0x00000000 && len >= 18) {
12486 n = QT_UINT16 ((guint8 *) data->data + 16);
12488 const gchar *genre;
12490 genre = gst_tag_id3_genre_get (n - 1);
12491 if (genre != NULL) {
12492 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
12493 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
12501 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
12502 const gchar * tag, guint8 * data, guint32 datasize)
12507 /* make a copy to have \0 at the end */
12508 datacopy = g_strndup ((gchar *) data, datasize);
12510 /* convert the str to double */
12511 if (sscanf (datacopy, "%lf", &value) == 1) {
12512 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
12513 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
12515 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
12523 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
12524 const char *tag, const char *tag_bis, GNode * node)
12533 const gchar *meanstr;
12534 const gchar *namestr;
12536 /* checking the whole ---- atom size for consistency */
12537 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
12538 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
12542 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
12544 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
12548 meansize = QT_UINT32 (mean->data);
12549 if (meansize <= 12) {
12550 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
12553 meanstr = ((gchar *) mean->data) + 12;
12556 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
12558 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
12562 namesize = QT_UINT32 (name->data);
12563 if (namesize <= 12) {
12564 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
12567 namestr = ((gchar *) name->data) + 12;
12575 * uint24 - data type
12579 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12581 GST_WARNING_OBJECT (demux, "No data atom in this tag");
12584 datasize = QT_UINT32 (data->data);
12585 if (datasize <= 16) {
12586 GST_WARNING_OBJECT (demux, "Data atom too small");
12589 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
12591 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
12592 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
12593 static const struct
12595 const gchar name[28];
12596 const gchar tag[28];
12599 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
12600 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
12601 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
12602 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
12603 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
12604 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
12605 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
12606 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
12610 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
12611 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
12612 switch (gst_tag_get_type (tags[i].tag)) {
12613 case G_TYPE_DOUBLE:
12614 qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
12615 ((guint8 *) data->data) + 16, datasize - 16);
12617 case G_TYPE_STRING:
12618 qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
12627 if (i == G_N_ELEMENTS (tags))
12637 #ifndef GST_DISABLE_GST_DEBUG
12639 gchar *namestr_dbg;
12640 gchar *meanstr_dbg;
12642 meanstr_dbg = g_strndup (meanstr, meansize);
12643 namestr_dbg = g_strndup (namestr, namesize);
12645 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
12646 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
12648 g_free (namestr_dbg);
12649 g_free (meanstr_dbg);
12656 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
12657 const char *tag_bis, GNode * node)
12662 GstTagList *id32_taglist = NULL;
12664 GST_LOG_OBJECT (demux, "parsing ID32");
12667 len = GST_READ_UINT32_BE (data);
12669 /* need at least full box and language tag */
12673 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
12674 gst_buffer_fill (buf, 0, data + 14, len - 14);
12676 id32_taglist = gst_tag_list_from_id3v2_tag (buf);
12677 if (id32_taglist) {
12678 GST_LOG_OBJECT (demux, "parsing ok");
12679 gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
12680 gst_tag_list_unref (id32_taglist);
12682 GST_LOG_OBJECT (demux, "parsing failed");
12685 gst_buffer_unref (buf);
12688 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
12689 const char *tag, const char *tag_bis, GNode * node);
12692 FOURCC_pcst -> if media is a podcast -> bool
12693 FOURCC_cpil -> if media is part of a compilation -> bool
12694 FOURCC_pgap -> if media is part of a gapless context -> bool
12695 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
12698 static const struct
12701 const gchar *gst_tag;
12702 const gchar *gst_tag_bis;
12703 const GstQTDemuxAddTagFunc func;
12706 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
12707 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
12708 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
12709 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
12710 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
12711 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
12712 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
12713 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
12714 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
12715 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
12716 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
12717 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
12718 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
12719 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12720 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12721 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12722 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
12723 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
12724 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
12725 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
12726 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
12727 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
12728 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
12729 qtdemux_tag_add_num}, {
12730 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
12731 qtdemux_tag_add_num}, {
12732 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
12733 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
12734 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
12735 FOURCC_covr, GST_TAG_IMAGE, NULL, qtdemux_tag_add_covr}, {
12736 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
12737 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
12738 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
12739 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
12740 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
12741 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
12742 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
12743 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
12744 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
12745 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
12746 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
12747 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
12748 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
12749 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
12750 qtdemux_tag_add_classification}, {
12751 FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
12752 FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
12753 FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
12755 /* This is a special case, some tags are stored in this
12756 * 'reverse dns naming', according to:
12757 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
12760 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
12761 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
12762 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
12765 struct _GstQtDemuxTagList
12768 GstTagList *taglist;
12770 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
12773 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
12779 const gchar *style;
12784 GstQTDemux *demux = qtdemuxtaglist->demux;
12785 GstTagList *taglist = qtdemuxtaglist->taglist;
12788 len = QT_UINT32 (data);
12789 buf = gst_buffer_new_and_alloc (len);
12790 gst_buffer_fill (buf, 0, data, len);
12792 /* heuristic to determine style of tag */
12793 if (QT_FOURCC (data + 4) == FOURCC_____ ||
12794 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
12796 else if (demux->major_brand == FOURCC_qt__)
12797 style = "quicktime";
12798 /* fall back to assuming iso/3gp tag style */
12802 /* santize the name for the caps. */
12803 for (i = 0; i < 4; i++) {
12804 guint8 d = data[4 + i];
12805 if (g_ascii_isalnum (d))
12806 ndata[i] = g_ascii_tolower (d);
12811 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
12812 ndata[0], ndata[1], ndata[2], ndata[3]);
12813 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
12815 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
12816 sample = gst_sample_new (buf, NULL, NULL, s);
12817 gst_buffer_unref (buf);
12818 g_free (media_type);
12820 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
12823 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
12824 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
12826 gst_sample_unref (sample);
12830 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
12837 GstQtDemuxTagList demuxtaglist;
12839 demuxtaglist.demux = qtdemux;
12840 demuxtaglist.taglist = taglist;
12842 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
12843 if (meta != NULL) {
12844 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
12845 if (ilst == NULL) {
12846 GST_LOG_OBJECT (qtdemux, "no ilst");
12851 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
12855 while (i < G_N_ELEMENTS (add_funcs)) {
12856 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
12860 len = QT_UINT32 (node->data);
12862 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
12863 GST_FOURCC_ARGS (add_funcs[i].fourcc));
12865 add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
12866 add_funcs[i].gst_tag_bis, node);
12868 g_node_destroy (node);
12874 /* parsed nodes have been removed, pass along remainder as blob */
12875 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
12876 (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
12878 /* parse up XMP_ node if existing */
12879 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
12880 if (xmp_ != NULL) {
12882 GstTagList *xmptaglist;
12884 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
12885 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
12886 xmptaglist = gst_tag_list_from_xmp_buffer (buf);
12887 gst_buffer_unref (buf);
12889 qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
12891 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
12897 GstStructure *structure; /* helper for sort function */
12899 guint min_req_bitrate;
12900 guint min_req_qt_version;
12904 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
12906 GstQtReference *ref_a = (GstQtReference *) a;
12907 GstQtReference *ref_b = (GstQtReference *) b;
12909 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
12910 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
12912 /* known bitrates go before unknown; higher bitrates go first */
12913 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
12916 /* sort the redirects and post a message for the application.
12919 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
12921 GstQtReference *best;
12924 GValue list_val = { 0, };
12927 g_assert (references != NULL);
12929 references = g_list_sort (references, qtdemux_redirects_sort_func);
12931 best = (GstQtReference *) references->data;
12933 g_value_init (&list_val, GST_TYPE_LIST);
12935 for (l = references; l != NULL; l = l->next) {
12936 GstQtReference *ref = (GstQtReference *) l->data;
12937 GValue struct_val = { 0, };
12939 ref->structure = gst_structure_new ("redirect",
12940 "new-location", G_TYPE_STRING, ref->location, NULL);
12942 if (ref->min_req_bitrate > 0) {
12943 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
12944 ref->min_req_bitrate, NULL);
12947 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
12948 g_value_set_boxed (&struct_val, ref->structure);
12949 gst_value_list_append_value (&list_val, &struct_val);
12950 g_value_unset (&struct_val);
12951 /* don't free anything here yet, since we need best->structure below */
12954 g_assert (best != NULL);
12955 s = gst_structure_copy (best->structure);
12957 if (g_list_length (references) > 1) {
12958 gst_structure_set_value (s, "locations", &list_val);
12961 g_value_unset (&list_val);
12963 for (l = references; l != NULL; l = l->next) {
12964 GstQtReference *ref = (GstQtReference *) l->data;
12966 gst_structure_free (ref->structure);
12967 g_free (ref->location);
12970 g_list_free (references);
12972 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
12973 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
12974 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
12975 qtdemux->posted_redirect = TRUE;
12978 /* look for redirect nodes, collect all redirect information and
12982 qtdemux_parse_redirects (GstQTDemux * qtdemux)
12984 GNode *rmra, *rmda, *rdrf;
12986 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
12988 GList *redirects = NULL;
12990 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
12992 GstQtReference ref = { NULL, NULL, 0, 0 };
12993 GNode *rmdr, *rmvc;
12995 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
12996 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
12997 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
12998 ref.min_req_bitrate);
13001 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
13002 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
13003 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
13005 #ifndef GST_DISABLE_GST_DEBUG
13006 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
13008 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
13010 GST_LOG_OBJECT (qtdemux,
13011 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
13012 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
13013 bitmask, check_type);
13014 if (package == FOURCC_qtim && check_type == 0) {
13015 ref.min_req_qt_version = version;
13019 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
13025 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
13026 if (ref_len > 20) {
13027 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
13028 ref_data = (guint8 *) rdrf->data + 20;
13029 if (ref_type == FOURCC_alis) {
13030 guint record_len, record_version, fn_len;
13032 if (ref_len > 70) {
13033 /* MacOSX alias record, google for alias-layout.txt */
13034 record_len = QT_UINT16 (ref_data + 4);
13035 record_version = QT_UINT16 (ref_data + 4 + 2);
13036 fn_len = QT_UINT8 (ref_data + 50);
13037 if (record_len > 50 && record_version == 2 && fn_len > 0) {
13038 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
13041 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
13044 } else if (ref_type == FOURCC_url_) {
13045 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
13047 GST_DEBUG_OBJECT (qtdemux,
13048 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
13049 GST_FOURCC_ARGS (ref_type));
13051 if (ref.location != NULL) {
13052 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
13054 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
13056 GST_WARNING_OBJECT (qtdemux,
13057 "Failed to extract redirect location from rdrf atom");
13060 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
13064 /* look for others */
13065 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
13068 if (redirects != NULL) {
13069 qtdemux_process_redirects (qtdemux, redirects);
13075 static GstTagList *
13076 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
13080 if (tags == NULL) {
13081 tags = gst_tag_list_new_empty ();
13082 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
13085 if (qtdemux->major_brand == FOURCC_mjp2)
13086 fmt = "Motion JPEG 2000";
13087 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
13089 else if (qtdemux->major_brand == FOURCC_qt__)
13091 else if (qtdemux->fragmented)
13094 fmt = "ISO MP4/M4A";
13096 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
13097 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
13099 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
13105 /* we have read the complete moov node now.
13106 * This function parses all of the relevant info, creates the traks and
13107 * prepares all data structures for playback
13110 qtdemux_parse_tree (GstQTDemux * qtdemux)
13116 GstClockTime duration;
13118 guint64 creation_time;
13119 GstDateTime *datetime = NULL;
13122 /* make sure we have a usable taglist */
13123 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13125 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
13126 if (mvhd == NULL) {
13127 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
13128 return qtdemux_parse_redirects (qtdemux);
13131 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
13132 if (version == 1) {
13133 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
13134 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
13135 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
13136 } else if (version == 0) {
13137 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
13138 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
13139 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
13141 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
13145 /* Moving qt creation time (secs since 1904) to unix time */
13146 if (creation_time != 0) {
13147 /* Try to use epoch first as it should be faster and more commonly found */
13148 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
13151 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
13152 /* some data cleansing sanity */
13153 g_get_current_time (&now);
13154 if (now.tv_sec + 24 * 3600 < creation_time) {
13155 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
13157 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
13160 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
13161 GDateTime *dt, *dt_local;
13163 dt = g_date_time_add_seconds (base_dt, creation_time);
13164 dt_local = g_date_time_to_local (dt);
13165 datetime = gst_date_time_new_from_g_date_time (dt_local);
13167 g_date_time_unref (base_dt);
13168 g_date_time_unref (dt);
13172 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
13173 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
13175 gst_date_time_unref (datetime);
13178 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
13179 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
13181 /* check for fragmented file and get some (default) data */
13182 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
13185 GstByteReader mehd_data;
13187 /* let track parsing or anyone know weird stuff might happen ... */
13188 qtdemux->fragmented = TRUE;
13190 /* compensate for total duration */
13191 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
13193 qtdemux_parse_mehd (qtdemux, &mehd_data);
13196 /* set duration in the segment info */
13197 gst_qtdemux_get_duration (qtdemux, &duration);
13199 qtdemux->segment.duration = duration;
13200 /* also do not exceed duration; stop is set that way post seek anyway,
13201 * and segment activation falls back to duration,
13202 * whereas loop only checks stop, so let's align this here as well */
13203 qtdemux->segment.stop = duration;
13206 /* parse all traks */
13207 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
13209 qtdemux_parse_trak (qtdemux, trak);
13210 /* iterate all siblings */
13211 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
13214 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13217 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
13219 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13221 GST_LOG_OBJECT (qtdemux, "No udta node found.");
13224 /* maybe also some tags in meta box */
13225 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
13227 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
13228 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13230 GST_LOG_OBJECT (qtdemux, "No meta node found.");
13233 /* parse any protection system info */
13234 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
13236 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
13237 qtdemux_parse_pssh (qtdemux, pssh);
13238 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
13241 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
13246 /* taken from ffmpeg */
13248 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
13260 len = (len << 7) | (c & 0x7f);
13268 /* this can change the codec originally present in @list */
13270 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
13271 QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
13273 int len = QT_UINT32 (esds->data);
13274 guint8 *ptr = esds->data;
13275 guint8 *end = ptr + len;
13277 guint8 *data_ptr = NULL;
13279 guint8 object_type_id = 0;
13280 const char *codec_name = NULL;
13281 GstCaps *caps = NULL;
13283 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
13285 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
13287 while (ptr + 1 < end) {
13288 tag = QT_UINT8 (ptr);
13289 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
13291 len = read_descr_size (ptr, end, &ptr);
13292 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
13294 /* Check the stated amount of data is available for reading */
13295 if (len < 0 || ptr + len > end)
13299 case ES_DESCRIPTOR_TAG:
13300 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
13301 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
13304 case DECODER_CONFIG_DESC_TAG:{
13305 guint max_bitrate, avg_bitrate;
13307 object_type_id = QT_UINT8 (ptr);
13308 max_bitrate = QT_UINT32 (ptr + 5);
13309 avg_bitrate = QT_UINT32 (ptr + 9);
13310 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
13311 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
13312 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
13313 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
13314 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
13315 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
13316 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
13317 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
13319 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
13320 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
13321 avg_bitrate, NULL);
13326 case DECODER_SPECIFIC_INFO_TAG:
13327 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
13328 if (object_type_id == 0xe0 && len == 0x40) {
13334 GST_DEBUG_OBJECT (qtdemux,
13335 "Have VOBSUB palette. Creating palette event");
13336 /* move to decConfigDescr data and read palette */
13338 for (i = 0; i < 16; i++) {
13339 clut[i] = QT_UINT32 (data);
13343 s = gst_structure_new ("application/x-gst-dvd", "event",
13344 G_TYPE_STRING, "dvd-spu-clut-change",
13345 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
13346 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
13347 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
13348 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
13349 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
13350 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
13351 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
13352 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
13355 /* store event and trigger custom processing */
13356 stream->pending_event =
13357 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
13359 /* Generic codec_data handler puts it on the caps */
13366 case SL_CONFIG_DESC_TAG:
13367 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
13371 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
13373 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
13379 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
13380 * in use, and should also be used to override some other parameters for some
13382 switch (object_type_id) {
13383 case 0x20: /* MPEG-4 */
13384 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
13385 * profile_and_level_indication */
13386 if (data_ptr != NULL && data_len >= 5 &&
13387 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
13388 gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
13389 data_ptr + 4, data_len - 4);
13391 break; /* Nothing special needed here */
13392 case 0x21: /* H.264 */
13393 codec_name = "H.264 / AVC";
13394 caps = gst_caps_new_simple ("video/x-h264",
13395 "stream-format", G_TYPE_STRING, "avc",
13396 "alignment", G_TYPE_STRING, "au", NULL);
13398 case 0x40: /* AAC (any) */
13399 case 0x66: /* AAC Main */
13400 case 0x67: /* AAC LC */
13401 case 0x68: /* AAC SSR */
13402 /* Override channels and rate based on the codec_data, as it's often
13404 /* Only do so for basic setup without HE-AAC extension */
13405 if (data_ptr && data_len == 2) {
13406 guint channels, rate;
13408 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
13410 entry->n_channels = channels;
13412 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
13414 entry->rate = rate;
13417 /* Set level and profile if possible */
13418 if (data_ptr != NULL && data_len >= 2) {
13419 gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
13420 data_ptr, data_len);
13422 const gchar *profile_str = NULL;
13425 guint8 *codec_data;
13426 gint rate_idx, profile;
13428 /* No codec_data, let's invent something.
13429 * FIXME: This is wrong for SBR! */
13431 GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
13433 buffer = gst_buffer_new_and_alloc (2);
13434 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
13435 codec_data = map.data;
13438 gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
13441 switch (object_type_id) {
13443 profile_str = "main";
13447 profile_str = "lc";
13451 profile_str = "ssr";
13459 codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
13461 ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
13463 gst_buffer_unmap (buffer, &map);
13464 gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
13465 GST_TYPE_BUFFER, buffer, NULL);
13466 gst_buffer_unref (buffer);
13469 gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
13470 G_TYPE_STRING, profile_str, NULL);
13474 case 0x60: /* MPEG-2, various profiles */
13480 codec_name = "MPEG-2 video";
13481 caps = gst_caps_new_simple ("video/mpeg",
13482 "mpegversion", G_TYPE_INT, 2,
13483 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13485 case 0x69: /* MPEG-2 BC audio */
13486 case 0x6B: /* MPEG-1 audio */
13487 caps = gst_caps_new_simple ("audio/mpeg",
13488 "mpegversion", G_TYPE_INT, 1, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
13489 codec_name = "MPEG-1 audio";
13491 case 0x6A: /* MPEG-1 */
13492 codec_name = "MPEG-1 video";
13493 caps = gst_caps_new_simple ("video/mpeg",
13494 "mpegversion", G_TYPE_INT, 1,
13495 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13497 case 0x6C: /* MJPEG */
13499 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13501 codec_name = "Motion-JPEG";
13503 case 0x6D: /* PNG */
13505 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
13507 codec_name = "PNG still images";
13509 case 0x6E: /* JPEG2000 */
13510 codec_name = "JPEG-2000";
13511 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
13513 case 0xA4: /* Dirac */
13514 codec_name = "Dirac";
13515 caps = gst_caps_new_empty_simple ("video/x-dirac");
13517 case 0xA5: /* AC3 */
13518 codec_name = "AC-3 audio";
13519 caps = gst_caps_new_simple ("audio/x-ac3",
13520 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13522 case 0xA9: /* AC3 */
13523 codec_name = "DTS audio";
13524 caps = gst_caps_new_simple ("audio/x-dts",
13525 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13527 case 0xE1: /* QCELP */
13528 /* QCELP, the codec_data is a riff tag (little endian) with
13529 * 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). */
13530 caps = gst_caps_new_empty_simple ("audio/qcelp");
13531 codec_name = "QCELP";
13537 /* If we have a replacement caps, then change our caps for this stream */
13539 gst_caps_unref (entry->caps);
13540 entry->caps = caps;
13543 if (codec_name && list)
13544 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
13545 GST_TAG_AUDIO_CODEC, codec_name, NULL);
13547 /* Add the codec_data attribute to caps, if we have it */
13551 buffer = gst_buffer_new_and_alloc (data_len);
13552 gst_buffer_fill (buffer, 0, data_ptr, data_len);
13554 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
13555 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
13557 gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
13559 gst_buffer_unref (buffer);
13564 static inline GstCaps *
13565 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
13569 char *s, fourstr[5];
13571 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13572 for (i = 0; i < 4; i++) {
13573 if (!g_ascii_isalnum (fourstr[i]))
13576 s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
13577 caps = gst_caps_new_empty_simple (s);
13582 #define _codec(name) \
13584 if (codec_name) { \
13585 *codec_name = g_strdup (name); \
13590 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13591 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
13592 const guint8 * stsd_entry_data, gchar ** codec_name)
13594 GstCaps *caps = NULL;
13595 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
13599 _codec ("PNG still images");
13600 caps = gst_caps_new_empty_simple ("image/png");
13603 _codec ("JPEG still images");
13605 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13608 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
13609 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
13610 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
13611 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
13612 _codec ("Motion-JPEG");
13614 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13617 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
13618 _codec ("Motion-JPEG format B");
13619 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
13622 _codec ("JPEG-2000");
13623 /* override to what it should be according to spec, avoid palette_data */
13624 entry->bits_per_sample = 24;
13625 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
13628 _codec ("Sorensen video v.3");
13629 caps = gst_caps_new_simple ("video/x-svq",
13630 "svqversion", G_TYPE_INT, 3, NULL);
13632 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
13633 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
13634 _codec ("Sorensen video v.1");
13635 caps = gst_caps_new_simple ("video/x-svq",
13636 "svqversion", G_TYPE_INT, 1, NULL);
13638 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
13639 caps = gst_caps_new_empty_simple ("video/x-raw");
13640 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
13641 _codec ("Windows Raw RGB");
13642 stream->alignment = 32;
13648 bps = QT_UINT16 (stsd_entry_data + 82);
13651 format = GST_VIDEO_FORMAT_RGB15;
13654 format = GST_VIDEO_FORMAT_RGB16;
13657 format = GST_VIDEO_FORMAT_RGB;
13660 format = GST_VIDEO_FORMAT_ARGB;
13668 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
13669 format = GST_VIDEO_FORMAT_I420;
13671 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
13672 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
13673 format = GST_VIDEO_FORMAT_I420;
13676 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
13677 format = GST_VIDEO_FORMAT_UYVY;
13679 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
13680 format = GST_VIDEO_FORMAT_v308;
13682 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
13683 format = GST_VIDEO_FORMAT_v216;
13686 format = GST_VIDEO_FORMAT_v210;
13688 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
13689 format = GST_VIDEO_FORMAT_r210;
13691 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
13692 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
13693 format = GST_VIDEO_FORMAT_v410;
13696 /* Packed YUV 4:4:4:4 8 bit in 32 bits
13697 * but different order than AYUV
13698 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
13699 format = GST_VIDEO_FORMAT_v408;
13702 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
13703 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
13704 _codec ("MPEG-1 video");
13705 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
13706 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13708 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
13709 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
13710 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
13711 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
13712 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
13713 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
13714 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
13715 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
13716 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
13717 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
13718 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
13719 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
13720 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
13721 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
13722 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
13723 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
13724 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
13725 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
13726 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
13727 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
13728 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
13729 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
13730 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
13731 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
13732 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
13733 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
13734 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
13735 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
13736 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
13737 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
13738 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
13739 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
13740 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
13741 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
13742 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
13743 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
13744 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
13745 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
13746 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
13747 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
13748 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
13749 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
13750 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
13751 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
13752 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
13753 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
13754 case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
13755 _codec ("MPEG-2 video");
13756 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
13757 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13759 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
13760 _codec ("GIF still images");
13761 caps = gst_caps_new_empty_simple ("image/gif");
13764 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
13766 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
13768 /* ffmpeg uses the height/width props, don't know why */
13769 caps = gst_caps_new_simple ("video/x-h263",
13770 "variant", G_TYPE_STRING, "itu", NULL);
13774 _codec ("MPEG-4 video");
13775 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
13776 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13778 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
13779 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
13780 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
13781 caps = gst_caps_new_simple ("video/x-msmpeg",
13782 "msmpegversion", G_TYPE_INT, 43, NULL);
13784 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
13786 caps = gst_caps_new_simple ("video/x-divx",
13787 "divxversion", G_TYPE_INT, 3, NULL);
13789 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
13790 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
13792 caps = gst_caps_new_simple ("video/x-divx",
13793 "divxversion", G_TYPE_INT, 4, NULL);
13795 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
13797 caps = gst_caps_new_simple ("video/x-divx",
13798 "divxversion", G_TYPE_INT, 5, NULL);
13801 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
13803 caps = gst_caps_new_simple ("video/x-ffv",
13804 "ffvversion", G_TYPE_INT, 1, NULL);
13807 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
13808 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
13813 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
13814 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
13815 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13819 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
13820 _codec ("Cinepak");
13821 caps = gst_caps_new_empty_simple ("video/x-cinepak");
13823 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
13824 _codec ("Apple QuickDraw");
13825 caps = gst_caps_new_empty_simple ("video/x-qdrw");
13827 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
13828 _codec ("Apple video");
13829 caps = gst_caps_new_empty_simple ("video/x-apple-video");
13833 _codec ("H.264 / AVC");
13834 caps = gst_caps_new_simple ("video/x-h264",
13835 "stream-format", G_TYPE_STRING, "avc",
13836 "alignment", G_TYPE_STRING, "au", NULL);
13839 _codec ("H.264 / AVC");
13840 caps = gst_caps_new_simple ("video/x-h264",
13841 "stream-format", G_TYPE_STRING, "avc3",
13842 "alignment", G_TYPE_STRING, "au", NULL);
13846 _codec ("H.265 / HEVC");
13847 caps = gst_caps_new_simple ("video/x-h265",
13848 "stream-format", G_TYPE_STRING, "hvc1",
13849 "alignment", G_TYPE_STRING, "au", NULL);
13852 _codec ("H.265 / HEVC");
13853 caps = gst_caps_new_simple ("video/x-h265",
13854 "stream-format", G_TYPE_STRING, "hev1",
13855 "alignment", G_TYPE_STRING, "au", NULL);
13858 _codec ("Run-length encoding");
13859 caps = gst_caps_new_simple ("video/x-rle",
13860 "layout", G_TYPE_STRING, "quicktime", NULL);
13863 _codec ("Run-length encoding");
13864 caps = gst_caps_new_simple ("video/x-rle",
13865 "layout", G_TYPE_STRING, "microsoft", NULL);
13867 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
13868 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
13869 _codec ("Indeo Video 3");
13870 caps = gst_caps_new_simple ("video/x-indeo",
13871 "indeoversion", G_TYPE_INT, 3, NULL);
13873 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
13874 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
13875 _codec ("Intel Video 4");
13876 caps = gst_caps_new_simple ("video/x-indeo",
13877 "indeoversion", G_TYPE_INT, 4, NULL);
13881 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
13882 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
13883 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
13884 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
13885 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
13886 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
13887 _codec ("DV Video");
13888 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
13889 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13891 case FOURCC_dv5n: /* DVCPRO50 NTSC */
13892 case FOURCC_dv5p: /* DVCPRO50 PAL */
13893 _codec ("DVCPro50 Video");
13894 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
13895 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13897 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
13898 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
13899 _codec ("DVCProHD Video");
13900 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
13901 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13903 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
13904 _codec ("Apple Graphics (SMC)");
13905 caps = gst_caps_new_empty_simple ("video/x-smc");
13907 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
13909 caps = gst_caps_new_empty_simple ("video/x-vp3");
13911 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
13912 _codec ("VP6 Flash");
13913 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
13917 caps = gst_caps_new_empty_simple ("video/x-theora");
13918 /* theora uses one byte of padding in the data stream because it does not
13919 * allow 0 sized packets while theora does */
13920 entry->padding = 1;
13924 caps = gst_caps_new_empty_simple ("video/x-dirac");
13926 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
13927 _codec ("TIFF still images");
13928 caps = gst_caps_new_empty_simple ("image/tiff");
13930 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
13931 _codec ("Apple Intermediate Codec");
13932 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
13934 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
13935 _codec ("AVID DNxHD");
13936 caps = gst_caps_from_string ("video/x-dnxhd");
13939 _codec ("On2 VP8");
13940 caps = gst_caps_from_string ("video/x-vp8");
13943 _codec ("Apple ProRes LT");
13945 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
13949 _codec ("Apple ProRes HQ");
13951 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
13955 _codec ("Apple ProRes");
13957 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13961 _codec ("Apple ProRes Proxy");
13963 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13967 _codec ("Apple ProRes 4444");
13969 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13973 _codec ("Apple ProRes 4444 XQ");
13975 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13979 _codec ("GoPro CineForm");
13980 caps = gst_caps_from_string ("video/x-cineform");
13985 caps = gst_caps_new_simple ("video/x-wmv",
13986 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
13988 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
13991 caps = _get_unknown_codec_name ("video", fourcc);
13996 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
13999 gst_video_info_init (&info);
14000 gst_video_info_set_format (&info, format, entry->width, entry->height);
14002 caps = gst_video_info_to_caps (&info);
14003 *codec_name = gst_pb_utils_get_codec_description (caps);
14005 /* enable clipping for raw video streams */
14006 stream->need_clip = TRUE;
14007 stream->alignment = 32;
14014 round_up_pow2 (guint n)
14026 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14027 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
14028 int len, gchar ** codec_name)
14031 const GstStructure *s;
14034 GstAudioFormat format = 0;
14037 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14039 depth = entry->bytes_per_packet * 8;
14042 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
14044 /* 8-bit audio is unsigned */
14046 format = GST_AUDIO_FORMAT_U8;
14047 /* otherwise it's signed and big-endian just like 'twos' */
14049 endian = G_BIG_ENDIAN;
14056 endian = G_LITTLE_ENDIAN;
14059 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
14061 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
14065 caps = gst_caps_new_simple ("audio/x-raw",
14066 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14067 "layout", G_TYPE_STRING, "interleaved", NULL);
14068 stream->alignment = GST_ROUND_UP_8 (depth);
14069 stream->alignment = round_up_pow2 (stream->alignment);
14072 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
14073 _codec ("Raw 64-bit floating-point audio");
14074 caps = gst_caps_new_simple ("audio/x-raw",
14075 "format", G_TYPE_STRING, "F64BE",
14076 "layout", G_TYPE_STRING, "interleaved", NULL);
14077 stream->alignment = 8;
14079 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
14080 _codec ("Raw 32-bit floating-point audio");
14081 caps = gst_caps_new_simple ("audio/x-raw",
14082 "format", G_TYPE_STRING, "F32BE",
14083 "layout", G_TYPE_STRING, "interleaved", NULL);
14084 stream->alignment = 4;
14087 _codec ("Raw 24-bit PCM audio");
14088 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14090 caps = gst_caps_new_simple ("audio/x-raw",
14091 "format", G_TYPE_STRING, "S24BE",
14092 "layout", G_TYPE_STRING, "interleaved", NULL);
14093 stream->alignment = 4;
14095 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
14096 _codec ("Raw 32-bit PCM audio");
14097 caps = gst_caps_new_simple ("audio/x-raw",
14098 "format", G_TYPE_STRING, "S32BE",
14099 "layout", G_TYPE_STRING, "interleaved", NULL);
14100 stream->alignment = 4;
14102 case GST_MAKE_FOURCC ('s', '1', '6', 'l'):
14103 _codec ("Raw 16-bit PCM audio");
14104 caps = gst_caps_new_simple ("audio/x-raw",
14105 "format", G_TYPE_STRING, "S16LE",
14106 "layout", G_TYPE_STRING, "interleaved", NULL);
14107 stream->alignment = 2;
14110 _codec ("Mu-law audio");
14111 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
14114 _codec ("A-law audio");
14115 caps = gst_caps_new_empty_simple ("audio/x-alaw");
14119 _codec ("Microsoft ADPCM");
14120 /* Microsoft ADPCM-ACM code 2 */
14121 caps = gst_caps_new_simple ("audio/x-adpcm",
14122 "layout", G_TYPE_STRING, "microsoft", NULL);
14126 _codec ("DVI/IMA ADPCM");
14127 caps = gst_caps_new_simple ("audio/x-adpcm",
14128 "layout", G_TYPE_STRING, "dvi", NULL);
14132 _codec ("DVI/Intel IMA ADPCM");
14133 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
14134 caps = gst_caps_new_simple ("audio/x-adpcm",
14135 "layout", G_TYPE_STRING, "quicktime", NULL);
14139 /* MPEG layer 3, CBR only (pre QT4.1) */
14141 _codec ("MPEG-1 layer 3");
14142 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
14143 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
14144 "mpegversion", G_TYPE_INT, 1, NULL);
14146 case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
14147 _codec ("MPEG-1 layer 2");
14149 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
14150 "mpegversion", G_TYPE_INT, 1, NULL);
14153 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
14154 _codec ("EAC-3 audio");
14155 caps = gst_caps_new_simple ("audio/x-eac3",
14156 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14157 entry->sampled = TRUE;
14159 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
14161 _codec ("AC-3 audio");
14162 caps = gst_caps_new_simple ("audio/x-ac3",
14163 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14164 entry->sampled = TRUE;
14166 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
14167 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
14168 _codec ("DTS audio");
14169 caps = gst_caps_new_simple ("audio/x-dts",
14170 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14171 entry->sampled = TRUE;
14173 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
14174 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
14175 _codec ("DTS-HD audio");
14176 caps = gst_caps_new_simple ("audio/x-dts",
14177 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14178 entry->sampled = TRUE;
14182 caps = gst_caps_new_simple ("audio/x-mace",
14183 "maceversion", G_TYPE_INT, 3, NULL);
14187 caps = gst_caps_new_simple ("audio/x-mace",
14188 "maceversion", G_TYPE_INT, 6, NULL);
14190 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
14192 caps = gst_caps_new_empty_simple ("application/ogg");
14194 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
14195 _codec ("DV audio");
14196 caps = gst_caps_new_empty_simple ("audio/x-dv");
14199 _codec ("MPEG-4 AAC audio");
14200 caps = gst_caps_new_simple ("audio/mpeg",
14201 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
14202 "stream-format", G_TYPE_STRING, "raw", NULL);
14204 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
14205 _codec ("QDesign Music");
14206 caps = gst_caps_new_empty_simple ("audio/x-qdm");
14209 _codec ("QDesign Music v.2");
14210 /* FIXME: QDesign music version 2 (no constant) */
14211 if (FALSE && data) {
14212 caps = gst_caps_new_simple ("audio/x-qdm2",
14213 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
14214 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
14215 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
14217 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
14221 _codec ("GSM audio");
14222 caps = gst_caps_new_empty_simple ("audio/x-gsm");
14225 _codec ("AMR audio");
14226 caps = gst_caps_new_empty_simple ("audio/AMR");
14229 _codec ("AMR-WB audio");
14230 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
14233 _codec ("Quicktime IMA ADPCM");
14234 caps = gst_caps_new_simple ("audio/x-adpcm",
14235 "layout", G_TYPE_STRING, "quicktime", NULL);
14238 _codec ("Apple lossless audio");
14239 caps = gst_caps_new_empty_simple ("audio/x-alac");
14242 _codec ("Free Lossless Audio Codec");
14243 caps = gst_caps_new_simple ("audio/x-flac",
14244 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14246 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
14247 _codec ("QualComm PureVoice");
14248 caps = gst_caps_from_string ("audio/qcelp");
14253 caps = gst_caps_new_empty_simple ("audio/x-wma");
14257 caps = gst_caps_new_empty_simple ("audio/x-opus");
14264 GstAudioFormat format;
14267 FLAG_IS_FLOAT = 0x1,
14268 FLAG_IS_BIG_ENDIAN = 0x2,
14269 FLAG_IS_SIGNED = 0x4,
14270 FLAG_IS_PACKED = 0x8,
14271 FLAG_IS_ALIGNED_HIGH = 0x10,
14272 FLAG_IS_NON_INTERLEAVED = 0x20
14274 _codec ("Raw LPCM audio");
14276 if (data && len >= 36) {
14277 depth = QT_UINT32 (data + 24);
14278 flags = QT_UINT32 (data + 28);
14279 width = QT_UINT32 (data + 32) * 8 / entry->n_channels;
14281 if ((flags & FLAG_IS_FLOAT) == 0) {
14286 if ((flags & FLAG_IS_ALIGNED_HIGH))
14289 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
14290 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
14291 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
14292 caps = gst_caps_new_simple ("audio/x-raw",
14293 "format", G_TYPE_STRING,
14295 GST_AUDIO_FORMAT_UNKNOWN ? gst_audio_format_to_string (format) :
14296 "UNKNOWN", "layout", G_TYPE_STRING,
14297 (flags & FLAG_IS_NON_INTERLEAVED) ? "non-interleaved" :
14298 "interleaved", NULL);
14299 stream->alignment = GST_ROUND_UP_8 (depth);
14300 stream->alignment = round_up_pow2 (stream->alignment);
14305 if (flags & FLAG_IS_BIG_ENDIAN)
14306 format = GST_AUDIO_FORMAT_F64BE;
14308 format = GST_AUDIO_FORMAT_F64LE;
14310 if (flags & FLAG_IS_BIG_ENDIAN)
14311 format = GST_AUDIO_FORMAT_F32BE;
14313 format = GST_AUDIO_FORMAT_F32LE;
14315 caps = gst_caps_new_simple ("audio/x-raw",
14316 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14317 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
14318 "non-interleaved" : "interleaved", NULL);
14319 stream->alignment = width / 8;
14323 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
14327 caps = _get_unknown_codec_name ("audio", fourcc);
14333 GstCaps *templ_caps =
14334 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
14335 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
14336 gst_caps_unref (caps);
14337 gst_caps_unref (templ_caps);
14338 caps = intersection;
14341 /* enable clipping for raw audio streams */
14342 s = gst_caps_get_structure (caps, 0);
14343 name = gst_structure_get_name (s);
14344 if (g_str_has_prefix (name, "audio/x-raw")) {
14345 stream->need_clip = TRUE;
14346 stream->max_buffer_size = 4096 * entry->bytes_per_frame;
14347 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
14353 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14354 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14355 const guint8 * stsd_entry_data, gchar ** codec_name)
14359 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14363 _codec ("DVD subtitle");
14364 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
14365 stream->need_process = TRUE;
14368 _codec ("Quicktime timed text");
14371 _codec ("3GPP timed text");
14373 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
14375 /* actual text piece needs to be extracted */
14376 stream->need_process = TRUE;
14379 _codec ("XML subtitles");
14380 caps = gst_caps_new_empty_simple ("application/ttml+xml");
14384 caps = _get_unknown_codec_name ("text", fourcc);
14392 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14393 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14394 const guint8 * stsd_entry_data, gchar ** codec_name)
14400 _codec ("MPEG 1 video");
14401 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14402 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14412 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
14413 const gchar * system_id)
14417 if (!qtdemux->protection_system_ids)
14418 qtdemux->protection_system_ids =
14419 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
14420 /* Check whether we already have an entry for this system ID. */
14421 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
14422 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
14423 if (g_ascii_strcasecmp (system_id, id) == 0) {
14427 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
14428 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,